Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
al_listen.cpp
Go to the documentation of this file.
1 #include "audiolib.h"
2 #ifdef HAVE_AL
3 #ifdef __APPLE__
4 #include <al.h>
5 #else
6 #include <AL/al.h>
7 #endif
8 #endif
9 #include <stdio.h>
10 #include <vector>
11 #include "al_globals.h"
12 #include "vs_globals.h"
13 #include "vsfilesystem.h"
14 #include "config_xml.h"
15 
16 using std::vector;
17 
18 struct Listener
19 {
22  Vector p, q, r;
23  float gain;
24  float rsize;
25  Listener() : pos( 0, 0, 0 )
26  , vel( 0, 0, 0 )
27  , p( 1, 0, 0 )
28  , q( 0, 1, 0 )
29  , r( 0, 0, 1 )
30  , gain( 1 )
31  , rsize( 1 ) {}
32 }
34 
35 unsigned int totalplaying = 0;
36 const unsigned int hashsize = 47;
37 
39 {
40  int soundname;
41 };
42 
43 typedef std::vector< ApproxSound >ApproxSoundVec;
45 unsigned int hash_sound( unsigned int buffer )
46 {
47  return buffer%hashsize;
48 }
49 
50 float AUDDistanceSquared( const int sound )
51 {
52 #ifdef HAVE_AL
53  return (sounds[sound].pos-mylistener.pos).MagnitudeSquared();
54 
55 #else
56  return 0.0;
57 #endif
58 }
59 
61 {
62  return mylistener.pos.Cast();
63 }
64 
65 static float EstimateGain(const Vector &pos, const float gain)
66 {
67  static float ref_distance = XMLSupport::parse_float( vs_config->getVariable( "audio", "audio_ref_distance", "4000" ) );
68 
69  // Base priority is source gain
70  float final_gain = gain;
71 
72  // Account for distance attenuation
73  float listener_size = sqrt(mylistener.rsize);
74  float distance = (AUDListenerLocation() - pos.Cast()).Magnitude()
75  - listener_size
76  - ref_distance;
77  float ref = ref_distance;
78  float rolloff = 1.0f;
79  final_gain *= (distance <= 0) ? 1.f : float(ref / (ref + rolloff * distance));
80 
81  return final_gain;
82 }
83 
84 char AUDQueryAudability( const int sound, const Vector &pos, const Vector &vel, const float gain )
85 {
86 #ifdef HAVE_AL
87  if (sounds[sound].buffer == (ALuint) 0)
88  return 0;
89  sounds[sound].pos = pos;
90  sounds[sound].vel = vel;
91  Vector t = pos-mylistener.pos;
92  float mag = t.Dot( t );
93  if ( pos == Vector( 0, 0, 0 ) ) {
94  t = Vector( 0, 0, 0 );
95  mag = 0;
96  return 1;
97  }
98  static float max_cutoff = XMLSupport::parse_float( vs_config->getVariable( "audio", "audio_cutoff_distance", "1000000" ) );
99  if ( !(mag < max_cutoff*max_cutoff) )
100  return 0;
101  unsigned int hashed = hash_sound( sounds[sound].buffer );
102  if ( ( !unusedsrcs.empty() ) && playingbuffers[hashed].size() < maxallowedsingle ) return 1;
104  if ( playingbuffers[hashed].empty() )
105  return 1;
106  //int target = rand()%playingbuffers[hashed].size();
107  float est_gain = EstimateGain(pos, gain);
108  float min_gain = est_gain;
109  int min_index = -1;
110  for (size_t target = 0; target < playingbuffers[hashed].size(); ++target) {
111  int target1 = playingbuffers[hashed][target].soundname;
112  t = sounds[target1].pos-mylistener.pos;
113  if ( sounds[target1].pos == Vector( 0, 0, 0 ) )
114  t = Vector( 0, 0, 0 );
115  //steal sound!
116  if (sounds[target1].buffer == sounds[sound].buffer) {
117  float target_est_gain;
118  if (sounds[target1].pos == Vector(0,0,0)) {
119  // relative sound, constant gain
120  target_est_gain = sounds[target1].gain;
121  } else {
122  // positional sound
123  target_est_gain = EstimateGain(sounds[target1].pos,sounds[target1].gain);
124  }
125  if (target_est_gain <= min_gain) {
126  min_index = target;
127  min_gain = target_est_gain;
128  }
129  }
130  }
131  if (min_index >= 0) {
132  int target = min_index;
133  int target1 = playingbuffers[hashed][target].soundname;
134 
135  ALuint tmpsrc = sounds[target1].source;
136 
137  sounds[target1].source = sounds[sound].source;
138  sounds[sound].source = tmpsrc;
139  playingbuffers[hashed][target].soundname = sound;
140  if (tmpsrc == 0) {
141  playingbuffers[hashed].erase( playingbuffers[hashed].begin()+target );
142  } else {
143  VSFileSystem::vs_dprintf (4, "stole %d",tmpsrc);
144  return 2;
145  }
146  }
147 
148  if (playingbuffers[hashed].size() > maxallowedsingle)
149  return 0;
150  if (totalplaying > maxallowedtotal)
151  return 0;
152 #endif
153  return 1;
154 }
155 
156 void AUDAddWatchedPlayed( const int sound, const Vector &pos )
157 {
158 #ifdef HAVE_AL
159  totalplaying++;
160  if (sounds[sound].buffer != (ALuint) 0) {
161  unsigned int h = hash_sound( sounds[sound].buffer );
162  if (sounds[sound].source == 0)
163  VSFileSystem::vs_fprintf( stderr, "adding null sound" );
164  playingbuffers[h].push_back( ApproxSound() );
165  playingbuffers[h].back().soundname = sound;
166  //VSFileSystem::vs_fprintf (stderr,"pushingback %f",(pos-mylistener.pos).Magnitude());
167  }
168 #endif
169 }
170 
171 typedef std::vector< int >vecint;
173 
175 {
176 #ifdef HAVE_AL
177  static unsigned int i = 0;
178  if (i >= hashsize) {
179  i = 0;
180  } else {
181  for (unsigned int j = 0; j < playingbuffers[i].size(); j++)
182  if ( !AUDIsPlaying( playingbuffers[i][j].soundname ) ) {
183  totalplaying--;
184  if (sounds[playingbuffers[i][j].soundname].source != (ALuint) 0) {
185  unusedsrcs.push_back( sounds[playingbuffers[i][j].soundname].source );
186  alSourcei( sounds[playingbuffers[i][j].soundname].source, AL_BUFFER, 0 );
187  sounds[playingbuffers[i][j].soundname].source = (ALuint) 0;
188  }
189  ApproxSoundVec::iterator k = playingbuffers[i].begin();
190  k += j;
191  playingbuffers[i].erase( k );
192  j--;
193  }
194  ++i;
195  }
196  static unsigned int j = 0;
197  if ( j >= soundstodelete.size() ) {
198  j = 0;
199  } else {
200  int tmp = soundstodelete[j];
201  if ( !AUDIsPlaying( tmp ) ) {
202  soundstodelete.erase( soundstodelete.begin()+j );
203  AUDDeleteSound( tmp, false );
204  }
205  ++j;
206  }
207 #endif
208 }
209 
210 void AUDListener( const QVector &pos, const Vector &vel )
211 {
212 #ifdef HAVE_AL
213  mylistener.pos = pos.Cast();
214  mylistener.vel = vel;
215  if (g_game.sound_enabled) {
216  if (usepositional)
217  alListener3f( AL_POSITION, scalepos*pos.i, scalepos*pos.j, scalepos*pos.k );
218  if (usedoppler)
219  alListener3f( AL_VELOCITY, scalevel*vel.i, scalevel*vel.j, scalevel*vel.k );
220  }
221  //printf ("(%f,%f,%f) <%f %f %f>\n",pos.i,pos.j,pos.k,vel.i,vel.j,vel.k);
222 #endif
223 }
224 
225 void AUDListenerSize( const float rSize )
226 {
227 #ifdef HAVE_AL
228  mylistener.rsize = rSize*rSize;
229 #endif
230 }
231 
232 void AUDListenerOrientation( const Vector &p, const Vector &q, const Vector &r )
233 {
234 #ifdef HAVE_AL
235  mylistener.p = p;
236  mylistener.q = q;
237  mylistener.r = r;
238  ALfloat orient[] = {r.i, r.j, r.k, q.i, q.j, q.k};
239  //printf ("R%f,%f,%f>Q<%f %f %f>",r.i,r.j,r.k,q.i,q.j,q.k);
240  if (g_game.sound_enabled)
241  alListenerfv( AL_ORIENTATION, orient );
242 #endif
243 }
244 
245 void AUDSoundGain( int sound, float gain, bool music )
246 {
247 #ifdef HAVE_AL
248  if ( sound >= 0 && sound < (int) sounds.size() ) {
249  sounds[sound].music = music;
250  float val = gain*(music ? 1.0f : mylistener.gain);
251  if (sounds[sound].source)
252  alSourcef( sounds[sound].source, AL_GAIN, val <= 1./16384 ? 0 : val );
253  sounds[sound].gain = gain;
254  //alSourcefv(sounds[sound].source,AL_VELOCITY,v);
255  }
256 #endif
257 }
258 
259 void AUDListenerGain( const float ggain )
260 {
261 #ifdef HAVE_AL
262  float gain = ggain;
263  if (gain <= 0) gain = 1./16384;
264  mylistener.gain = gain;
265  for (unsigned int i = 0, ie = sounds.size(); i < ie; ++i)
266  if (!sounds[i].music)
267  AUDSoundGain( i, sounds[i].gain, false );
268  if (g_game.sound_enabled)
269  alListenerf( AL_GAIN, 1.0 );
270 #endif
271 }
272 
274 {
275 #ifdef HAVE_AL
276  return mylistener.gain;
277 
278 #else
279  return 0;
280 #endif
281 }
282