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_sound.cpp
Go to the documentation of this file.
1 #include "audiolib.h"
2 #include "hashtable.h"
3 #include "vsfilesystem.h"
4 #include <string>
5 #include "al_globals.h"
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include "cmd/unit_generic.h"
9 #include "gfx/cockpit_generic.h"
10 #ifdef HAVE_AL
11 
12 typedef struct /* WAV File-header */
13 {
14  ALubyte Id[4];
15  ALsizei Size;
16  ALubyte Type[4];
17 } WAVFileHdr_Struct;
18 
19 typedef struct /* WAV Fmt-header */
20 {
21  ALushort Format;
22  ALushort Channels;
23  ALuint SamplesPerSec;
24  ALuint BytesPerSec;
25  ALushort BlockAlign;
26  ALushort BitsPerSample;
27 } WAVFmtHdr_Struct;
28 
29 typedef struct /* WAV FmtEx-header */
30 {
31  ALushort Size;
32  ALushort SamplesPerBlock;
33 } WAVFmtExHdr_Struct;
34 
35 typedef struct /* WAV Smpl-header */
36 {
37  ALuint Manufacturer;
38  ALuint Product;
39  ALuint SamplePeriod;
40  ALuint Note;
41  ALuint FineTune;
42  ALuint SMPTEFormat;
43  ALuint SMPTEOffest;
44  ALuint Loops;
45  ALuint SamplerData;
46  struct
47  {
48  ALuint Identifier;
49  ALuint Type;
50  ALuint Start;
51  ALuint End;
52  ALuint Fraction;
53  ALuint Count;
54  } Loop[1];
55 } WAVSmplHdr_Struct;
56 
57 typedef struct /* WAV Chunk-header */
58 {
59  ALubyte Id[4];
60  ALuint Size;
61 } WAVChunkHdr_Struct;
62 
63 void SwapWords( unsigned int *puint )
64 {
65  unsigned int tempint = POSH_LittleU32( *puint );
66  *puint = tempint;
67 }
68 
69 void SwapBytes( unsigned short *pshort )
70 {
71  unsigned short tempshort = POSH_LittleU16( *pshort );
72  *pshort = tempshort;
73 }
74 
75 void blutLoadWAVMemory( ALbyte *memory, ALenum
76  *format, ALvoid **data, ALsizei *size, ALsizei *freq, ALboolean *loop )
77 {
78  WAVChunkHdr_Struct ChunkHdr;
79  WAVFmtExHdr_Struct FmtExHdr;
80  WAVFileHdr_Struct FileHdr;
81  WAVSmplHdr_Struct SmplHdr;
82  WAVFmtHdr_Struct FmtHdr;
83  ALbyte *Stream;
84 
85  *format = AL_FORMAT_MONO16;
86  *data = NULL;
87  *size = 0;
88  *freq = 22050;
89  *loop = AL_FALSE;
90  if (memory) {
91  Stream = memory;
92  if (Stream) {
93  memcpy( &FileHdr, Stream, sizeof (WAVFileHdr_Struct) );
94  Stream += sizeof (WAVFileHdr_Struct);
95  SwapWords( (unsigned int*) &FileHdr.Size );
96  FileHdr.Size = ( (FileHdr.Size+1)&~1 )-4;
97  while ( (FileHdr.Size != 0) && ( memcpy( &ChunkHdr, Stream, sizeof (WAVChunkHdr_Struct) ) ) ) {
98  Stream += sizeof (WAVChunkHdr_Struct);
99  SwapWords( &ChunkHdr.Size );
100  if ( (ChunkHdr.Id[0] == 'f') && (ChunkHdr.Id[1] == 'm') && (ChunkHdr.Id[2] == 't')
101  && (ChunkHdr.Id[3] == ' ') ) {
102  memcpy( &FmtHdr, Stream, sizeof (WAVFmtHdr_Struct) );
103  SwapBytes( &FmtHdr.Format );
104  if (FmtHdr.Format == 0x0001) {
105  SwapBytes( &FmtHdr.Channels );
106  SwapBytes( &FmtHdr.BitsPerSample );
107  SwapWords( &FmtHdr.SamplesPerSec );
108  SwapBytes( &FmtHdr.BlockAlign );
109 
110  *format = ( FmtHdr.Channels == 1
111  ? (FmtHdr.BitsPerSample == 8 ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16)
112  : (FmtHdr.BitsPerSample == 8 ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16) );
113  *freq = FmtHdr.SamplesPerSec;
114  Stream += ChunkHdr.Size;
115  } else {
116  memcpy( &FmtExHdr, Stream, sizeof (WAVFmtExHdr_Struct) );
117  Stream += ChunkHdr.Size;
118  }
119  } else if ( (ChunkHdr.Id[0] == 'd') && (ChunkHdr.Id[1] == 'a') && (ChunkHdr.Id[2] == 't')
120  && (ChunkHdr.Id[3] == 'a') ) {
121  if (FmtHdr.Format == 0x0001) {
122  *size = ChunkHdr.Size;
123  if (*data == NULL)
124  *data = malloc( ChunkHdr.Size+31 );
125  else
126  *data = realloc( *data, ChunkHdr.Size+31 );
127  if (*data) {
128  memcpy( *data, Stream, ChunkHdr.Size );
129  memset( ( (char*) *data )+ChunkHdr.Size, 0, 31 );
130  Stream += ChunkHdr.Size;
131  if (FmtHdr.BitsPerSample == 16)
132  for (size_t i = 0; i < (ChunkHdr.Size/2); ++i)
133  SwapBytes( &(*(unsigned short**) data)[i] );
134  }
135  } else if (FmtHdr.Format == 0x0011) {
136  //IMA ADPCM
137  } else if (FmtHdr.Format == 0x0055) {
138  //MP3 WAVE
139  }
140  } else if ( (ChunkHdr.Id[0] == 's') && (ChunkHdr.Id[1] == 'm') && (ChunkHdr.Id[2] == 'p')
141  && (ChunkHdr.Id[3] == 'l') ) {
142  memcpy( &SmplHdr, Stream, sizeof (WAVSmplHdr_Struct) );
143  Stream += ChunkHdr.Size;
144  } else {Stream += ChunkHdr.Size; } Stream += ChunkHdr.Size&1;
145  FileHdr.Size -= ( ( (ChunkHdr.Size+1)&~1 )+8 );
146  }
147  }
148  }
149 }
150 
151 #ifdef __APPLE__
152 #include <al.h>
153 #include <alc.h>
154 //#include <alut.h>
155 #include <fcntl.h>
156 #include <sys/types.h>
157 #include <sys/stat.h>
158 //their LoadWav is b0rken seriously!!!!!!
159 
160 #else
161 #include <AL/al.h>
162 #include <AL/alc.h>
163 
164 #endif
165 //#include <AL/alext.h>
166 #endif
167 #include <vector>
168 #include "vs_globals.h"
169 #include <algorithm>
170 #include <stdio.h>
171 #ifdef HAVE_AL
172 #ifdef HAVE_OGG
173 
174 #include <vorbis/vorbisfile.h>
175 #endif
176 std::vector< unsigned int >dirtysounds;
177 std::vector< OurSound > sounds;
178 std::vector< ALuint >buffers;
179 
180 static void convertToLittle( unsigned int tmp, char *data )
181 {
182  data[0] = (char) (tmp%256);
183  data[1] = (char) ( (tmp/256)%256 );
184  data[2] = (char) ( (tmp/65536)%256 );
185  data[3] = (char) ( (tmp/65536)/256 );
186 }
187 
188 #ifdef HAVE_OGG
189 struct fake_file
190 {
191  char *data;
192  size_t size;
193  size_t loc;
194 };
195 
196 size_t mem_read( void *ptr, size_t size, size_t nmemb, void *datasource )
197 {
198  fake_file *fp = (fake_file*) datasource;
199  if (fp->loc+size > fp->size) {
200  size_t tmp = fp->size-fp->loc;
201  if (tmp)
202  memcpy( ptr, fp->data+fp->loc, tmp );
203  fp->loc = fp->size;
204  return tmp;
205  } else {
206  memcpy( ptr, fp->data+fp->loc, size );
207  fp->loc += size;
208  return size;
209  }
210 }
211 
212 int mem_close( void* )
213 {
214  return 0;
215 }
216 
217 long mem_tell( void *datasource )
218 {
219  fake_file *fp = (fake_file*) datasource;
220  return (long) fp->loc;
221 }
222 
223 int cant_seek( void *datasource, ogg_int64_t offset, int whence )
224 {
225  return -1;
226 }
227 
228 int mem_seek( void *datasource, ogg_int64_t offset, int whence )
229 {
230  fake_file *fp = (fake_file*) datasource;
231  if (whence == SEEK_END) {
232  if (offset < 0) {
233  if (fp->size < (size_t) -offset) {
234  return -1;
235  } else {
236  fp->loc = fp->size+offset;
237  return 0;
238  }
239  } else if (offset == 0) {
240  fp->loc = fp->size;
241  } else {return -1; }} else if (whence == SEEK_CUR) {
242  if (offset < 0) {
243  if (fp->loc < (size_t) -offset) {
244  return -1;
245  } else {
246  fp->loc += offset;
247  return 0;
248  }
249  } else {
250  if (fp->loc+offset > fp->size) {
251  return -1;
252  } else {
253  fp->loc += offset;
254  return 0;
255  }
256  }
257  } else if (whence == SEEK_SET) {
258  if (offset > static_cast<int>(fp->size))
259  return -1;
260  fp->loc = offset;
261  return 0;
262  }
263  return -1;
264 }
265 
266 #endif
267 
268 static void ConvertFormat( vector< char > &ogg )
269 {
270  vector< char >converted;
271  if (ogg.size() > 4) {
272  if (ogg[0] == 'O' && ogg[1] == 'g' && ogg[2] == 'g' && ogg[3] == 'S') {
273 #ifdef HAVE_OGG
274  OggVorbis_File vf;
275  ov_callbacks callbacks;
276  fake_file ff;
277 
278  ff.data = &ogg[0];
279  ff.loc = 0;
280  ff.size = ogg.size();
281  callbacks.read_func = &mem_read;
282  callbacks.seek_func = &mem_seek;
283  callbacks.close_func = &mem_close;
284  callbacks.tell_func = &mem_tell;
285  if ( ov_open_callbacks( &ff, &vf, NULL, 0, callbacks ) ) {
286  ogg.clear();
287  } else {
288  long bytesread = 0;
289  vorbis_info *info = ov_info( &vf, -1 );
290  const int segmentsize = 65536*32;
291  const int samples = 16;
292  converted.push_back( 'R' );
293  converted.push_back( 'I' );
294  converted.push_back( 'F' );
295  converted.push_back( 'F' );
296  converted.push_back( 0 );
297  converted.push_back( 0 );
298  converted.push_back( 0 );
299  converted.push_back( 0 ); //fill in with weight;
300  converted.push_back( 'W' );
301  converted.push_back( 'A' );
302  converted.push_back( 'V' );
303  converted.push_back( 'E' );
304  converted.push_back( 'f' );
305  converted.push_back( 'm' );
306  converted.push_back( 't' );
307  converted.push_back( ' ' );
308 
309  converted.push_back( 18 ); //size of header (16 bytes)
310  converted.push_back( 0 );
311  converted.push_back( 0 );
312  converted.push_back( 0 );
313 
314  converted.push_back( 1 ); //compression code
315  converted.push_back( 0 );
316 
317  converted.push_back( (char) (info->channels%256) ); //num channels;
318  converted.push_back( (char) (info->channels/256) );
319 
320  converted.push_back( 0 ); //sample rate
321  converted.push_back( 0 ); //sample rate
322  converted.push_back( 0 ); //sample rate
323  converted.push_back( 0 ); //sample rate
324  convertToLittle( info->rate, &converted[converted.size()-4] );
325 
326  long byterate = info->rate*info->channels*samples/8;
327  converted.push_back( 0 ); //bytes per second rate
328  converted.push_back( 0 );
329  converted.push_back( 0 );
330  converted.push_back( 0 );
331  convertToLittle( byterate, &converted[converted.size()-4] );
332 
333  converted.push_back( (char) ( (info->channels*samples/8)%256 ) ); //num_channels*16 bits/8
334  converted.push_back( (char) ( (info->channels*samples/8)/256 ) );
335 
336  converted.push_back( samples ); //16 bit samples
337  converted.push_back( 0 );
338  converted.push_back( 0 );
339  converted.push_back( 0 );
340 
341  //PCM header
342  converted.push_back( 'd' );
343  converted.push_back( 'a' );
344  converted.push_back( 't' );
345  converted.push_back( 'a' );
346 
347  converted.push_back( 0 );
348  converted.push_back( 0 );
349  converted.push_back( 0 );
350  converted.push_back( 0 );
351  ogg_int64_t pcmsizestart = converted.size();
352  converted.resize( converted.size()+segmentsize );
353  int signedvalue = 1;
354  int bitstream = 0;
355  while ( ( bytesread =
356  ov_read( &vf, &converted[converted.size()-segmentsize], segmentsize, 0, samples/8, signedvalue,
357  &bitstream ) ) > 0 ) {
358  int numtoerase = 0;
359  if (bytesread < segmentsize)
360  numtoerase = segmentsize-bytesread;
361 
362  converted.resize( converted.size()+segmentsize-numtoerase );
363  }
364  converted.resize( converted.size()-segmentsize );
365  convertToLittle( converted.size()-8, &converted[4] );
366  convertToLittle( converted.size()-pcmsizestart, &converted[pcmsizestart-4] );
367 
368  converted.swap( ogg );
369  }
370  ov_clear( &vf );
371 #else
372  ogg.clear();
373 #endif
374  }
375  }
376 }
377 
378 static int LoadSound( ALuint buffer, bool looping, bool music )
379 {
380  unsigned int i;
381  if ( !dirtysounds.empty() ) {
382  i = dirtysounds.back();
383  dirtysounds.pop_back();
384  //assert (sounds[i].buffer==(ALuint)0);
385  if (sounds[i].buffer != (ALuint) 0)
386  VSFileSystem::vs_dprintf( 3, "using claimed buffer %d\n", sounds[i].buffer );
387  sounds[i].buffer = buffer;
388  } else {
389  i = sounds.size();
390  sounds.push_back( OurSound( 0, buffer ) );
391  }
392  sounds[i].source = (ALuint) 0;
393  sounds[i].looping = looping ? AL_TRUE : AL_FALSE;
394  sounds[i].music = music;
395 #ifdef SOUND_DEBUG
396  printf( " with buffer %d and looping property %d\n", i, (int) looping );
397 #endif
398  //limited number of sources
399  //alGenSources( 1, &sounds[i].source);
400  //alSourcei(sounds[i].source, AL_BUFFER, buffer );
401  //alSourcei(sounds[i].source, AL_LOOPING, looping ?AL_TRUE:AL_FALSE);
402  return i;
403 }
404 
405 #endif
406 
407 using namespace VSFileSystem;
408 
409 bool AUDLoadSoundFile( const char *s, struct AUDSoundProperties *info, bool use_fileptr )
410 {
411  VSFileSystem::vs_dprintf(3, "Loading sound file %s\n", s);
412 
413  info->success = false;
414  vector< char >dat;
415  if (use_fileptr) {
416  FILE *f = fopen( s, "rb" );
417  if (!f) {
418  std::string path = std::string( "sounds/" )+s;
419  f = fopen( path.c_str(), "rb" );
420  }
421  if (!f) {
422  std::string path = std::string( "music/" )+s;
423  f = fopen( path.c_str(), "rb" );
424  }
425  if (f) {
426  fseek( f, 0, SEEK_END );
427  size_t siz = ftell( f );
428  fseek( f, 0, SEEK_SET );
429  dat.resize( siz );
430  size_t bogus_return_var; //added by chuck_starchaser to get rid of warning
431  bogus_return_var = fread( &dat[0], 1, siz, f );
432  info->hashname = s;
433  info->shared = false;
434  fclose( f );
435  } else {
436  return false;
437  }
438  } else {
439  VSFile f;
441  if (error > Ok)
442  error = f.OpenReadOnly( s, UnknownFile );
443  info->shared = (error == Shared);
444  if (info->shared)
445  info->hashname = VSFileSystem::GetSharedSoundHashName( s );
446  else
447  info->hashname = VSFileSystem::GetHashName( s );
448  if (error > Ok)
449  return false;
450 #ifdef SOUND_DEBUG
451  printf( "Sound %s created with and alBuffer %d\n", s.c_str(), *wavbuf );
452 #endif
453  dat.resize( f.Size() );
454  f.Read( &dat[0], f.Size() );
455  f.Close();
456  }
457  ConvertFormat( dat );
458  if (dat.size() == 0) //conversion messed up
459  return false;
460  //blutLoadWAVMemory((ALbyte *)&dat[0], &format, &wave, &size, &freq, &looping);
461 
462 #if 0
463  ALint format;
464  //MAC OS X
465  if (error <= Ok)
466  MacFixedLoadWAVFile( &dat[0], &format, &wave, &size, &freq );
467 #else
468  blutLoadWAVMemory( (ALbyte*) &dat[0], &info->format, &info->wave, &info->size, &info->freq, &info->looping );
469 #endif
470  if (!info->wave)
471  return false; //failure.
472 
473  info->success = true;
474  return true;
475 }
476 
477 int AUDBufferSound( const struct AUDSoundProperties *info, bool music )
478 {
479  ALuint wavbuf = 0;
480 #ifdef HAVE_AL
481  alGenBuffers( 1, &wavbuf );
482  if (!wavbuf) printf( "OpenAL Error in alGenBuffers: %d\n", alGetError() );
483  alBufferData( wavbuf, info->format, info->wave, info->size, info->freq );
484 #endif
485  return LoadSound( wavbuf, info->looping, music );
486 }
487 
488 #ifdef HAVE_AL
489 ALuint
490 #else
491 unsigned int
492 #endif
494 
495 int AUDCreateSoundWAV( const std::string &s, const bool music, const bool LOOP )
496 {
497 #ifdef HAVE_AL
498 #ifdef SOUND_DEBUG
499  printf( "AUDCreateSoundWAV:: " );
500 #endif
501  if ( (g_game.sound_enabled && !music) || (g_game.music_enabled && music) ) {
502  ALuint *wavbuf = NULL;
503  std::string hashname;
504  if (!music) {
505  hashname = VSFileSystem::GetHashName( s );
506  wavbuf = soundHash.Get( hashname );
507  if (!wavbuf) {
508  hashname = VSFileSystem::GetSharedSoundHashName( s );
509  wavbuf = soundHash.Get( hashname );
510  }
511  if (wavbuf == &nil_wavebuf)
512  return -1; //404
513  }
514  if (wavbuf) {
515 #ifdef SOUND_DEBUG
516  printf( "Sound %s restored with alBuffer %d\n", s.c_str(), *wavbuf );
517 #endif
518  }
519  if (wavbuf == NULL) {
520  AUDSoundProperties info;
521  if ( !AUDLoadSoundFile( s.c_str(), &info ) ) {
522  soundHash.Put( info.hashname, &nil_wavebuf );
523  return -1;
524  }
525  wavbuf = (ALuint*) malloc( sizeof (ALuint) );
526  alGenBuffers( 1, wavbuf );
527  alBufferData( *wavbuf, info.format, info.wave, info.size, info.freq );
528  free( info.wave ); //alutUnloadWAV(format,wave,size,freq);
529  if (!music) {
530  soundHash.Put( info.hashname, wavbuf );
531  buffers.push_back( *wavbuf );
532  }
533  }
534  return LoadSound( *wavbuf, LOOP, music );
535  }
536 #endif
537  return -1;
538 }
539 
540 int AUDCreateSoundWAV( const std::string &s, const bool LOOP )
541 {
542  return AUDCreateSoundWAV( s, false, LOOP );
543 }
544 
545 int AUDCreateMusicWAV( const std::string &s, const bool LOOP )
546 {
547  return AUDCreateSoundWAV( s, true, LOOP );
548 }
549 
550 int AUDCreateSoundMP3( const std::string &s, const bool music, const bool LOOP )
551 {
552 #ifdef HAVE_AL
553  assert( 0 );
554  if ( (g_game.sound_enabled && !music) || (g_game.music_enabled && music) ) {
555  VSFile f;
556  VSError error = f.OpenReadOnly( s.c_str(), SoundFile );
557  bool shared = (error == Shared);
558  std::string nam( s );
559  ALuint *mp3buf = NULL;
560  std::string hashname;
561  if (!music) {
562  hashname = shared ? VSFileSystem::GetSharedSoundHashName( s ) : VSFileSystem::GetHashName( s );
563  mp3buf = soundHash.Get( hashname );
564  }
565  if (error > Ok)
566  return -1;
567 #ifdef _WIN32
568  return -1;
569 #endif
570  if (mp3buf == NULL) {
571  char *data = new char[f.Size()];
572  f.Read( data, f.Size() );
573  mp3buf = (ALuint*) malloc( sizeof (ALuint) );
574  alGenBuffers( 1, mp3buf );
575  /*
576  * if ((*alutLoadMP3p)(*mp3buf,data,f.Size())!=AL_TRUE) {
577  * delete []data;
578  * return -1;
579  * }*/
580  delete[] data;
581  if (!music) {
582  soundHash.Put( hashname, mp3buf );
583  buffers.push_back( *mp3buf );
584  }
585  } else {
586  f.Close();
587  }
588  return LoadSound( *mp3buf, LOOP, music );
589  }
590 #endif
591  return -1;
592 }
593 
594 int AUDCreateSoundMP3( const std::string &s, const bool LOOP )
595 {
596  return AUDCreateSoundMP3( s, false, LOOP );
597 }
598 
599 int AUDCreateMusicMP3( const std::string &s, const bool LOOP )
600 {
601  return AUDCreateSoundMP3( s, true, LOOP );
602 }
603 
604 int AUDCreateSound( const std::string &s, const bool LOOP )
605 {
606  if ( s.end()-1 >= s.begin() ) {
607  if (*(s.end()-1) == '3')
608  return AUDCreateSoundMP3( s, LOOP );
609  else
610  return AUDCreateSoundWAV( s, LOOP );
611  }
612  return -1;
613 }
614 
615 int AUDCreateMusic( const std::string &s, const bool LOOP )
616 {
617  if ( s.end()-1 >= s.begin() ) {
618  if (*(s.end()-1) == 'v')
619  return AUDCreateMusicWAV( s, LOOP );
620  else
621  return AUDCreateMusicMP3( s, LOOP );
622  }
623  return -1;
624 }
625 
627 int AUDCreateSound( int sound, const bool LOOP /*=false*/ )
628 {
629 #ifdef HAVE_AL
630  if ( AUDIsPlaying( sound ) )
631  AUDStopPlaying( sound );
632  if ( sound >= 0 && sound < (int) sounds.size() )
633  return LoadSound( sounds[sound].buffer, LOOP, false );
634 #endif
635  return -1;
636 }
637 
638 extern std::vector< int >soundstodelete;
639 void AUDDeleteSound( int sound, bool music )
640 {
641 #ifdef HAVE_AL
642  if ( sound >= 0 && sound < (int) sounds.size() ) {
643  if ( AUDIsPlaying( sound ) ) {
644  if (!music) {
645 #ifdef SOUND_DEBUG
646  printf( "AUDDeleteSound: Sound Playing enqueue soundstodelete %d %d\n",
647  sounds[sound].source,
648  sounds[sound].buffer );
649 #endif
650  soundstodelete.push_back( sound );
651  return;
652  } else {
653  AUDStopPlaying( sound );
654  }
655  }
656 #ifdef SOUND_DEBUG
657  printf( "AUDDeleteSound: Sound Not Playing push back to unused src %d %d\n", sounds[sound].source, sounds[sound].buffer );
658 #endif
659  if (sounds[sound].source) {
660  unusedsrcs.push_back( sounds[sound].source );
661  alSourcei( sounds[sound].source, AL_BUFFER, 0 ); //decrement the source refcount
662  sounds[sound].source = (ALuint) 0;
663  }
664 #ifdef SOUND_DEBUG
665  if ( std::find( dirtysounds.begin(), dirtysounds.end(), sound ) == dirtysounds.end() ) {
666 #endif
667  dirtysounds.push_back( sound );
668 #ifdef SOUND_DEBUG
669  } else {
670  VSFileSystem::vs_fprintf( stderr, "double delete of sound %d", sound );
671  return;
672  }
673 #endif
674  //FIXME??
675  //alDeleteSources(1,&sounds[sound].source);
676  if (music)
677  alDeleteBuffers( 1, &sounds[sound].buffer );
678  sounds[sound].buffer = (ALuint) 0;
679  }
680 #endif
681 }
682 
683 void AUDAdjustSound( const int sound, const QVector &pos, const Vector &vel )
684 {
685  static float ref_distance = XMLSupport::parse_float( vs_config->getVariable( "audio", "audio_ref_distance", "4000" ) );
686  static float max_distance = XMLSupport::parse_float( vs_config->getVariable( "audio", "audio_max_distance", "1000000" ) );
687 
688 #ifdef HAVE_AL
689  if ( sound >= 0 && sound < (int) sounds.size() ) {
690  float p[] = {
691  scalepos *pos.i, scalepos*pos.j, scalepos*pos.k
692  }
693  ;
694  float v[] = {scalevel *vel.i, scalevel*vel.j, scalevel*vel.k};
695  sounds[sound].pos = pos.Cast();
696  sounds[sound].vel = vel;
697  if (usepositional && sounds[sound].source) {
698  alSourcefv( sounds[sound].source, AL_POSITION, p );
699  bool relative = (p[0] == 0 && p[1] == 0 && p[2] == 0);
700  alSourcei( sounds[sound].source, AL_SOURCE_RELATIVE, relative );
701  if (!relative) {
702  // Set rolloff factrs
703  alSourcef(sounds[sound].source, AL_MAX_DISTANCE, scalepos * max_distance);
704  alSourcef(sounds[sound].source, AL_REFERENCE_DISTANCE, scalepos * ref_distance);
705  alSourcef(sounds[sound].source, AL_ROLLOFF_FACTOR, 1.f);
706  }
707  }
708  if (usedoppler && sounds[sound].source)
709  alSourcefv( sounds[sound].source, AL_VELOCITY, v );
710  }
711 #endif
712 }
713 
714 void AUDStreamingSound( const int sound )
715 {
716 #ifdef HAVE_AL
717  if (sound >= 0 && sound < (int) sounds.size() && sounds[sound].source) {
718  alSource3f( sounds[sound].source, AL_POSITION, 0.0, 0.0, 0.0 );
719  alSource3f( sounds[sound].source, AL_VELOCITY, 0.0, 0.0, 0.0 );
720  alSource3f( sounds[sound].source, AL_DIRECTION, 0.0, 0.0, 0.0 );
721  alSourcef( sounds[sound].source, AL_ROLLOFF_FACTOR, 0.0 );
722  alSourcei( sounds[sound].source, AL_SOURCE_RELATIVE, AL_TRUE );
723  }
724 #endif
725 }
726 
728 {
729  if ( !_Universe || !_Universe->AccessCockpit( 0 ) )
730  return true; //No Universe yet, so game is loading.
731 
732  Unit *playa = _Universe->AccessCockpit( 0 )->GetParent();
733  if (!playa)
734  return false;
735  return playa->getStarSystem() == _Universe->activeStarSystem();
736 }
737 
739 {
740  int retval = -1;
741 #ifdef HAVE_AL
742  unsigned int s = ::sounds.size();
743  for (unsigned int i = 0; i < s; ++i)
744  if (false == ::sounds[i].music && AUDIsPlaying( i ) && false == ::sounds[i].looping)
745  retval = i;
746 #endif
747  return retval;
748 }
749 
750 void AUDStopAllSounds( int except_this_one )
751 {
752 #ifdef HAVE_AL
753  unsigned int s = ::sounds.size();
754  for (unsigned int i = 0; i < s; ++i)
755  if ( (int) i != except_this_one && false == ::sounds[i].music && AUDIsPlaying( i ) )
756  AUDStopPlaying( i );
757 #endif
758 }
759 
760 bool AUDIsPlaying( const int sound )
761 {
762 #ifdef HAVE_AL
763  if ( sound >= 0 && sound < (int) sounds.size() ) {
764  if (!sounds[sound].source)
765  return false;
766  ALint state;
767 #if defined (_WIN32) || defined (__APPLE__)
768  alGetSourcei( sounds[sound].source, AL_SOURCE_STATE, &state ); //Obtiene el estado de la fuente para windows
769 #else
770  alGetSourceiv( sounds[sound].source, AL_SOURCE_STATE, &state );
771 #endif
772 
773  return state == AL_PLAYING;
774  }
775 #endif
776  return false;
777 }
778 
779 void AUDStopPlaying( const int sound )
780 {
781 #ifdef HAVE_AL
782  if ( sound >= 0 && sound < (int) sounds.size() ) {
783 #ifdef SOUND_DEBUG
784  printf( "AUDStopPlaying sound %d source(releasing): %d buffer:%d\n", sound, sounds[sound].source, sounds[sound].buffer );
785 #endif
786  if (sounds[sound].source != 0) {
787  alSourceStop( sounds[sound].source );
788  unusedsrcs.push_back( sounds[sound].source );
789  alSourcei( sounds[sound].source, AL_BUFFER, 0 ); //decrement refcount
790  }
791  sounds[sound].source = (ALuint) 0;
792  }
793 #endif
794 }
795 
796 static bool AUDReclaimSource( const int sound, bool high_priority = false )
797 {
798 #ifdef HAVE_AL
799  if (sounds[sound].source == (ALuint) 0) {
800  if (!sounds[sound].buffer)
801  return false;
802  if ( unusedsrcs.empty() ) {
803  if (high_priority) {
804  unsigned int i;
805  unsigned int candidate = 0;
806  bool found = false;
807  for (i = 0; i < sounds.size(); ++i)
808  if (sounds[i].source != 0)
809  if (sounds[i].pos.i != 0 || sounds[i].pos.j != 0 || sounds[i].pos.k != 0) {
810  if (found) {
811  if ( AUDDistanceSquared( candidate ) < AUDDistanceSquared( i ) )
812  candidate = i;
813  } else {
814  candidate = i;
815  }
816  found = true;
817  }
818  if (!found) {
819  return false;
820  } else {
821  alSourceStop( sounds[candidate].source );
822  sounds[sound].source = sounds[candidate].source;
823  alSourcei( sounds[candidate].source, AL_BUFFER, 0 ); //reclaim the source
824  sounds[candidate].source = 0;
825  }
826  } else {
827  return false;
828  }
829  } else {
830  sounds[sound].source = unusedsrcs.back();
831  unusedsrcs.pop_back();
832  }
833  alSourcei( sounds[sound].source, AL_BUFFER, sounds[sound].buffer );
834  alSourcei( sounds[sound].source, AL_LOOPING, sounds[sound].looping );
835  }
836  return true;
837 #endif
838  return false; //silly
839 }
840 
841 void AUDStartPlaying( const int sound )
842 {
843 #ifdef SOUND_DEBUG
844  printf( "AUDStartPlaying(%d)", sound );
845 #endif
846 
847 #ifdef HAVE_AL
848  if ( sound >= 0 && sound < (int) sounds.size() ) {
849  if ( sounds[sound].music || starSystemOK() )
850  if ( AUDReclaimSource( sound, sounds[sound].pos == QVector( 0, 0, 0 ) ) ) {
851 #ifdef SOUND_DEBUG
852  printf( "AUDStartPlaying sound %d source:%d buffer:%d\n", sound, sounds[sound].source, sounds[sound].buffer );
853 #endif
854  AUDAdjustSound( sound, sounds[sound].pos, sounds[sound].vel );
855  AUDSoundGain( sound, sounds[sound].gain, sounds[sound].music );
856  alSourcePlay( sounds[sound].source );
857  }
858  }
859 #endif
860 }
861 
862 void AUDPlay( const int sound, const QVector &pos, const Vector &vel, const float gain )
863 {
864 #ifdef HAVE_AL
865  char tmp;
866  if (sound < 0)
867  return;
868  if (sounds[sound].buffer == 0)
869  return;
870  if (!starSystemOK() && !sounds[sound].music)
871  return;
872  if ( AUDIsPlaying( sound ) )
873  AUDStopPlaying( sound );
874  if ( ( tmp = AUDQueryAudability( sound, pos.Cast(), vel, gain ) ) != 0 ) {
875  if ( AUDReclaimSource( sound, pos == QVector( 0, 0, 0 ) ) ) {
876  AUDAdjustSound( sound, pos, vel );
877  AUDSoundGain( sound, gain, sounds[sound].music );
878  if (tmp != 2) {
879  VSFileSystem::vs_dprintf(3, "AUDPlay sound %d %d\n",
880  sounds[sound].source, sounds[sound].buffer );
881  AUDAddWatchedPlayed( sound, pos.Cast() );
882  } else {
883  VSFileSystem::vs_dprintf(3, "AUDPlay stole sound %d %d\n",
884  sounds[sound].source, sounds[sound].buffer );
885  alSourceStop( sounds[sound].source );
886  }
887  alSourcePlay( sounds[sound].source );
888  }
889  }
890 #endif
891 }
892 
893 #ifndef AL_SEC_OFFSET
894 /* Supported on Windows, but the headers might be out of date. */
895 #define AL_SEC_OFFSET 0x1024
896 #endif
897 
898 float AUDGetCurrentPosition( const int sound )
899 {
900 #ifdef HAVE_AL
901  ALfloat rv;
902  alGetSourcef( sound, AL_SEC_OFFSET, &rv );
903  return float(rv);
904 #else
905  return 0;
906 #endif
907 }
908 
909 void AUDPausePlaying( const int sound )
910 {
911 #ifdef HAVE_AL
912  if ( sound >= 0 && sound < (int) sounds.size() ) {
913  //alSourcePlay( sounds[sound].source() );
914  }
915 #endif
916 }
917