1
2
3 #ifdef _WIN32
4 #define VC_EXTRALEAN
5 #ifndef STRICT
6 #define STRICT
7 #endif
8
9 #include <windows.h>
10 #include <mmsystem.h>
11 #endif
12
13 #include "cfile/cfile.h"
14 #include "globalincs/pstypes.h"
15 #include "io/timer.h"
16 #include "sound/audiostr.h"
17 #include "sound/ds.h"
18 #include "sound/IAudioFile.h"
19 #include "sound/sound.h"
20 #include "sound/openal.h"
21 #include "gamesnd/eventmusic.h"
22
23 #ifdef WITH_FFMPEG
24 #include "sound/ffmpeg/FFmpegWaveFile.h"
25 #endif
26
27 #define MAX_STREAM_BUFFERS 4
28
29 // status
30 #define ASF_FREE 0
31 #define ASF_USED 1
32
33 // constants
34 #define BIGBUF_SIZE 176400
35 ubyte *Wavedata_load_buffer = NULL; // buffer used for cueing audiostreams
36 ubyte *Wavedata_service_buffer = NULL; // buffer used for servicing audiostreams
37
38 SDL_mutex* Global_service_lock;
39
40 typedef bool (*TIMERCALLBACK)(ptr_u);
41
42 #define COMPRESSED_BUFFER_SIZE 176400
43 ubyte *Compressed_buffer = NULL; // Used to load in compressed data during a cueing interval
44 ubyte *Compressed_service_buffer = NULL; // Used to read in compressed data during a service interval
45
46 // Globalize the list of audio extensions for use in several sound related files
47 const char *audio_ext_list[] = { ".ogg", ".wav" };
48 const int NUM_AUDIO_EXT = sizeof(audio_ext_list) / sizeof(char*);
49
openAudioFile(const char * fileName,bool keep_ext)50 static std::unique_ptr<sound::IAudioFile> openAudioFile(const char* fileName, bool keep_ext) {
51 #ifdef WITH_FFMPEG
52 {
53 std::unique_ptr<sound::IAudioFile> audio_file(new sound::ffmpeg::FFmpegWaveFile());
54
55 // Open given file
56 if (audio_file->Open(fileName, keep_ext)) {
57 return audio_file;
58 }
59 }
60 #endif
61
62 return nullptr;
63 }
64
openAudioMem(const uint8_t * snddata,size_t snd_len)65 static std::unique_ptr<sound::IAudioFile> openAudioMem(const uint8_t* snddata, size_t snd_len) {
66 #ifdef WITH_FFMPEG
67 {
68 std::unique_ptr<sound::IAudioFile> audio_file(new sound::ffmpeg::FFmpegWaveFile());
69
70 // Open given in-memory file
71 if (audio_file->OpenMem(snddata, snd_len)) {
72 return audio_file;
73 }
74 }
75 #endif
76
77 return nullptr;
78 }
79
80 int Audiostream_inited = 0;
81
82 class Timer
83 {
84 public:
85 void constructor();
86 void destructor();
87 bool Create (uint nPeriod, uint nRes, ptr_u dwUser, TIMERCALLBACK pfnCallback);
88 protected:
89 static uint TimeProc(uint interval, void *param);
90 TIMERCALLBACK m_pfnCallback;
91 ptr_u m_dwUser;
92 uint m_nPeriod;
93 uint m_nRes;
94 SDL_TimerID m_nIDTimer;
95 };
96
97 class AudioStream
98 {
99 public:
100 AudioStream ();
101 ~AudioStream ();
102 bool Create (char *pszFilename);
103 bool CreateMem (const uint8_t* snddata, size_t snd_len);
104 bool Destroy ();
105 void Play (float volume, int looping);
Is_Playing()106 bool Is_Playing(){ return m_fPlaying; }
Is_Paused()107 bool Is_Paused(){ return m_bIsPaused; }
Is_Past_Limit()108 bool Is_Past_Limit() { return m_bPastLimit; }
109 void Stop (int paused = 0);
110 void Stop_and_Rewind ();
111 void Fade_and_Destroy ();
112 void Fade_and_Stop();
113 void Set_Volume(float vol);
114 float Get_Volume();
115 void Init_Data();
116 void Set_Sample_Cutoff(uint sample_cutoff);
Set_Default_Volume(float vol)117 void Set_Default_Volume(float vol) { m_lDefaultVolume = vol; }
Get_Default_Volume()118 float Get_Default_Volume() { return m_lDefaultVolume; }
119 uint Get_Samples_Committed();
Is_looping()120 int Is_looping() { return m_bLooping; }
121 int status;
122 int type;
123 bool paused_via_sexp_or_script;
124
125 protected:
126 bool prepareOpened(const char *filename);
127 void Cue ();
128 bool WriteWaveData (uint cbSize, uint *num_bytes_written, int service = 1);
129 uint GetMaxWriteSize ();
130 bool ServiceBuffer ();
131 static bool TimerCallback (ptr_u dwUser);
132 bool PlaybackDone();
133
134 ALuint m_source_id; // name of openAL source
135 ALuint m_buffer_ids[MAX_STREAM_BUFFERS]; // names of buffers
136
137 Timer m_timer; // ptr to Timer object
138 std::unique_ptr<sound::IAudioFile> m_pwavefile; // ptr to WaveFile object
139 sound::AudioFileProperties m_fileProps;
140 bool m_fCued; // semaphore (stream cued)
141 bool m_fPlaying; // semaphore (stream playing)
142 uint m_cbBufOffset; // last write position
143 uint m_cbBufSize; // size of sound buffer in bytes
144 uint m_nBufService; // service interval in msec
145 uint m_nTimeStarted; // time (in system time) playback started
146
147 bool m_bLooping; // whether or not to loop playback
148 bool m_bFade; // fade out music
149 bool m_bDestroy_when_faded;
150 float m_lVolume; // volume of stream ( 0 -> 1 )
151 float m_lCutoffVolume;
152 bool m_bIsPaused; // stream is stopped, but not rewinded
153 bool m_bReadingDone; // no more bytes to be read from disk, still have remaining buffer to play
154 uint m_fade_timer_id; // timestamp so we know when to start fade
155 uint m_finished_id; // timestamp so we know when we've played #bytes required
156 bool m_bPastLimit; // flag to show we've played past the number of bytes requred
157 float m_lDefaultVolume;
158
159 size_t m_total_uncompressed_bytes_read;
160 size_t m_max_uncompressed_bytes_to_read;
161
162 SDL_mutex* write_lock;
163
164 };
165
166
167 // Timer class implementation
168 //
169 ////////////////////////////////////////////////////////////
170
171 // constructor
constructor(void)172 void Timer::constructor(void)
173 {
174 m_nIDTimer = 0;
175 }
176
177
178 // Destructor
destructor(void)179 void Timer::destructor(void)
180 {
181 if (m_nIDTimer) {
182 SDL_RemoveTimer(m_nIDTimer);
183 m_nIDTimer = 0;
184 }
185 }
186
187 // Create
Create(uint nPeriod,uint nRes,ptr_u dwUser,TIMERCALLBACK pfnCallback)188 bool Timer::Create (uint nPeriod, uint nRes, ptr_u dwUser, TIMERCALLBACK pfnCallback)
189 {
190 bool bRtn = true; // assume success
191
192 Assert(pfnCallback);
193 Assert(nPeriod > 10);
194 Assert(nPeriod >= nRes);
195
196 m_nPeriod = nPeriod;
197 m_nRes = nRes;
198 m_dwUser = dwUser;
199 m_pfnCallback = pfnCallback;
200
201 if ((m_nIDTimer = SDL_AddTimer(m_nPeriod, TimeProc, (void*)this)) == 0) {
202 bRtn = false;
203 }
204
205 return (bRtn);
206 }
207
208
209 // Timer proc for multimedia timer callback set with timeSetTime().
210 //
211 // Calls procedure specified when Timer object was created. The
212 // dwUser parameter contains "this" pointer for associated Timer object.
213 //
TimeProc(uint interval,void * dwUser)214 uint Timer::TimeProc(uint interval, void *dwUser)
215 {
216 // dwUser contains ptr to Timer object
217 Timer * ptimer = (Timer *) dwUser;
218
219 // Call user-specified callback and pass back user specified data
220 (ptimer->m_pfnCallback) (ptimer->m_dwUser);
221
222 if (ptimer->m_nPeriod) {
223 return interval;
224 } else {
225 SDL_RemoveTimer(ptimer->m_nIDTimer);
226 ptimer->m_nIDTimer = 0;
227 return 0;
228 }
229 }
230
231 //
232 // AudioStream class implementation
233 //
234 ////////////////////////////////////////////////////////////
235
236 // The following constants are the defaults for our streaming buffer operation.
237 const ushort DefBufferServiceInterval = 250; // default buffer service interval in msec
238
239 // Constructor
AudioStream(void)240 AudioStream::AudioStream (void) : m_total_uncompressed_bytes_read(0), m_max_uncompressed_bytes_to_read(0)
241 {
242 write_lock = SDL_CreateMutex();
243 }
244
245 // Destructor
~AudioStream(void)246 AudioStream::~AudioStream (void)
247 {
248 SDL_DestroyMutex( write_lock );
249 }
250
Init_Data()251 void AudioStream::Init_Data ()
252 {
253 m_bLooping = 0;
254 m_bFade = false;
255 m_fade_timer_id = 0;
256 m_finished_id = 0;
257 m_bPastLimit = false;
258
259 m_bDestroy_when_faded = false;
260 m_lVolume = 1.0f;
261 m_lCutoffVolume = 0.0f;
262 m_bIsPaused = false;
263 m_bReadingDone = false;
264
265 m_pwavefile = nullptr;
266 m_fPlaying = m_fCued = false;
267 m_cbBufOffset = 0;
268 m_cbBufSize = 0;
269 m_nBufService = DefBufferServiceInterval;
270 m_nTimeStarted = 0;
271
272 memset(m_buffer_ids, 0, sizeof(m_buffer_ids));
273 m_source_id = 0;
274
275 m_total_uncompressed_bytes_read = 0;
276 m_max_uncompressed_bytes_to_read = std::numeric_limits<size_t>::max();
277 }
278
279
prepareOpened(const char * filename)280 bool AudioStream::prepareOpened(const char *filename)
281 {
282 bool fRtn = true;
283
284 m_fileProps = m_pwavefile->getFileProperties();
285
286 m_cbBufSize = (m_fileProps.sample_rate * m_fileProps.bytes_per_sample * m_fileProps.num_channels) >> 2;
287 // make sure that we are a multiple of the frame size
288 m_cbBufSize -= (m_cbBufSize % (m_fileProps.bytes_per_sample * m_fileProps.num_channels));
289 m_cbBufSize += (m_cbBufSize % 12) << 1;
290 // if the requested buffer size is too big then cap it
291 m_cbBufSize = (m_cbBufSize > BIGBUF_SIZE) ? BIGBUF_SIZE : m_cbBufSize;
292
293 // nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
294
295 OpenAL_ErrorCheck( alGenSources(1, &m_source_id), { fRtn = false; goto ErrorExit; } );
296
297 OpenAL_ErrorCheck( alGenBuffers(MAX_STREAM_BUFFERS, m_buffer_ids), { fRtn = false; goto ErrorExit; } );
298
299 OpenAL_ErrorPrint( alSourcef(m_source_id, AL_ROLLOFF_FACTOR, 1.0f) );
300 OpenAL_ErrorPrint( alSourcei(m_source_id, AL_SOURCE_RELATIVE, AL_TRUE) );
301
302 OpenAL_ErrorPrint( alSource3f(m_source_id, AL_POSITION, 0.0f, 0.0f, 0.0f) );
303 OpenAL_ErrorPrint( alSource3f(m_source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f) );
304
305 OpenAL_ErrorPrint( alSourcef(m_source_id, AL_GAIN, 1.0f) );
306 OpenAL_ErrorPrint( alSourcef(m_source_id, AL_PITCH, 1.0f) );
307
308 // maybe set EFX
309 if ( (type == ASF_SOUNDFX) && ds_eax_is_inited() ) {
310 extern ALuint AL_EFX_aux_id;
311 OpenAL_ErrorPrint( alSource3i(m_source_id, AL_AUXILIARY_SEND_FILTER, AL_EFX_aux_id, 0, AL_FILTER_NULL) );
312 }
313
314 Snd_sram += (m_cbBufSize * MAX_STREAM_BUFFERS);
315
316 ErrorExit:
317 if ( (fRtn == false) && (m_pwavefile) ) {
318 mprintf(("AUDIOSTR => ErrorExit for ::prepareOpened() on wave file: %s\n", filename));
319
320 if (m_source_id)
321 OpenAL_ErrorPrint( alDeleteSources(1, &m_source_id) );
322
323 m_pwavefile = nullptr;
324 }
325
326 return fRtn;
327 }
328
329 // Create
Create(char * pszFilename)330 bool AudioStream::Create (char *pszFilename)
331 {
332 Assert(pszFilename);
333
334 Init_Data();
335
336 if ( ! pszFilename )
337 return false;
338 // make 100% sure we got a good filename
339 if ( !strlen(pszFilename) )
340 return false;
341
342 // Create a new WaveFile object and open it
343 m_pwavefile = openAudioFile(pszFilename, (type == ASF_EVENTMUSIC));
344 if (m_pwavefile) {
345 return prepareOpened(pszFilename);
346 }
347 else {
348 // Error, unable to create WaveFile object
349 nprintf(("Sound", "SOUND => Failed to open wave file %s\n", pszFilename));
350 return false;
351 }
352
353 }
354
CreateMem(const uint8_t * snddata,size_t snd_len)355 bool AudioStream::CreateMem (const uint8_t* snddata, size_t snd_len)
356 {
357 Init_Data();
358
359 // Create a new WaveFile object and open it
360 m_pwavefile = openAudioMem(snddata, snd_len);
361 if (m_pwavefile) {
362 return prepareOpened("in-memory");
363 }
364 else {
365 // Error, unable to create WaveFile object
366 nprintf(("Sound", "SOUND => Failed to open in-memory wave file \n"));
367 return false;
368 }
369 }
370
371 // Destroy
Destroy(void)372 bool AudioStream::Destroy (void)
373 {
374 bool fRtn = true;
375 ALint buffers_processed = 0;
376
377 SDL_LockMutex(write_lock);
378
379 // Stop playback
380 Stop ();
381
382 OpenAL_ErrorPrint( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed) );
383
384 while (buffers_processed) {
385 ALuint buffer_id = 0;
386 OpenAL_ErrorPrint( alSourceUnqueueBuffers(m_source_id, 1, &buffer_id) );
387 buffers_processed--;
388 }
389
390 // Release sound sources and buffers
391 OpenAL_ErrorPrint( alDeleteSources(1, &m_source_id) );
392 OpenAL_ErrorPrint( alDeleteBuffers(MAX_STREAM_BUFFERS, m_buffer_ids) );
393
394 Snd_sram -= (m_cbBufSize * MAX_STREAM_BUFFERS);
395
396 // Delete WaveFile object
397 m_pwavefile = nullptr;
398
399 status = ASF_FREE;
400
401 SDL_UnlockMutex(write_lock);
402
403 return fRtn;
404 }
405
406 // WriteWaveData
407 //
408 // Writes wave data to sound buffer. This is a helper method used by Create and
409 // ServiceBuffer; it's not exposed to users of the AudioStream class.
WriteWaveData(uint size,uint * num_bytes_written,int service)410 bool AudioStream::WriteWaveData (uint size, uint *num_bytes_written, int service)
411 {
412 bool fRtn = true;
413 ubyte *uncompressed_wave_data;
414
415 *num_bytes_written = 0;
416
417 if ( size == 0 || m_bReadingDone ) {
418 return fRtn;
419 }
420
421 if ( (m_buffer_ids[0] == 0) || !m_pwavefile ) {
422 return fRtn;
423 }
424
425 if ( service ) {
426 SDL_LockMutex(Global_service_lock);
427 }
428
429 if ( service ) {
430 uncompressed_wave_data = Wavedata_service_buffer;
431 } else {
432 uncompressed_wave_data = Wavedata_load_buffer;
433 }
434
435 int num_bytes_read = 0;
436
437 const auto alFormat = openal_get_format(m_fileProps.bytes_per_sample * 8, m_fileProps.num_channels);
438
439 if ( !service ) {
440 for (int ib = 0; ib < MAX_STREAM_BUFFERS; ib++) {
441 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize);
442
443 // if looping then maybe reset wavefile and keep going
444 if ( (num_bytes_read < 0) && m_bLooping) {
445 m_pwavefile->Cue();
446 m_total_uncompressed_bytes_read = 0;
447 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize);
448 }
449
450 if (num_bytes_read < 0) {
451 m_bReadingDone = 1;
452 break;
453 } else if (num_bytes_read > 0) {
454 OpenAL_ErrorCheck( alBufferData(m_buffer_ids[ib], alFormat, uncompressed_wave_data, num_bytes_read, m_fileProps.sample_rate), { fRtn = false; goto ErrorExit; } );
455 OpenAL_ErrorCheck( alSourceQueueBuffers(m_source_id, 1, &m_buffer_ids[ib]), { fRtn = false; goto ErrorExit; } );
456
457 *num_bytes_written += num_bytes_read;
458 }
459 }
460 } else {
461 ALint buffers_processed = 0;
462 OpenAL_ErrorPrint( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed) );
463
464 while (buffers_processed) {
465 ALuint buffer_id = 0;
466 OpenAL_ErrorPrint( alSourceUnqueueBuffers(m_source_id, 1, &buffer_id) );
467
468 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize);
469
470 // if looping then maybe reset wavefile and keep going
471 if ( (num_bytes_read < 0) && m_bLooping) {
472 m_pwavefile->Cue();
473 m_total_uncompressed_bytes_read = 0;
474 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize);
475 }
476
477 if (num_bytes_read < 0) {
478 m_bReadingDone = 1;
479 } else if (num_bytes_read > 0) {
480 OpenAL_ErrorPrint( alBufferData(buffer_id, alFormat, uncompressed_wave_data, num_bytes_read, m_fileProps.sample_rate) );
481 OpenAL_ErrorPrint( alSourceQueueBuffers(m_source_id, 1, &buffer_id) );
482
483 *num_bytes_written += num_bytes_read;
484 }
485
486 buffers_processed--;
487 }
488 }
489
490 ErrorExit:
491 m_total_uncompressed_bytes_read += *num_bytes_written;
492
493 if ( service ) {
494 SDL_UnlockMutex(Global_service_lock);
495 }
496
497 return (fRtn);
498 }
499
500 // GetMaxWriteSize
501 //
502 // Helper function to calculate max size of sound buffer write operation, i.e. how much
503 // free space there is in buffer.
GetMaxWriteSize(void)504 uint AudioStream::GetMaxWriteSize (void)
505 {
506 uint dwMaxSize = m_cbBufSize;
507 ALint n, q;
508
509 OpenAL_ErrorCheck( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &n), return 0 );
510
511 OpenAL_ErrorCheck( alGetSourcei(m_source_id, AL_BUFFERS_QUEUED, &q), return 0 );
512
513 if (!n && (q >= MAX_STREAM_BUFFERS)) //all buffers queued
514 dwMaxSize = 0;
515
516 // nprintf(("Alan","Max write size: %d\n", dwMaxSize));
517 return (dwMaxSize);
518 }
519
520 #define VOLUME_ATTENUATION_BEFORE_CUTOFF 0.03f
521 #define VOLUME_ATTENUATION 0.65f
ServiceBuffer(void)522 bool AudioStream::ServiceBuffer (void)
523 {
524 float vol;
525 bool fRtn = true;
526
527 if ( status != ASF_USED )
528 return false;
529
530 SDL_LockMutex( write_lock );
531
532 // status may have changed, so lets check once again
533 if ( status != ASF_USED ){
534 SDL_UnlockMutex( write_lock );
535
536 return false;
537 }
538
539 if ( m_bFade == true ) {
540 if ( m_lCutoffVolume == 0.0f ) {
541 vol = Get_Volume();
542 // nprintf(("Alan","Volume is: %d\n",vol));
543 m_lCutoffVolume = vol * VOLUME_ATTENUATION_BEFORE_CUTOFF;
544 }
545
546 vol = Get_Volume() * VOLUME_ATTENUATION;
547 // nprintf(("Alan","Volume is now: %d\n",vol));
548 Set_Volume(vol);
549
550 // nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
551 // nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
552 if ( vol < m_lCutoffVolume ) {
553 m_bFade = false;
554 m_lCutoffVolume = 0.0f;
555
556 if ( m_bDestroy_when_faded == true ) {
557 SDL_UnlockMutex( write_lock );
558
559 Destroy();
560 // Reset reentrancy semaphore
561
562 return false;
563 } else {
564 Stop_and_Rewind();
565 // Reset reentrancy semaphore
566 SDL_UnlockMutex( write_lock );
567
568 return true;
569 }
570 }
571 }
572
573 // All of sound not played yet, send more data to buffer
574 uint dwFreeSpace = GetMaxWriteSize ();
575
576 // Determine free space in sound buffer
577 if (dwFreeSpace) {
578
579 // Some wave data remains, but not enough to fill free space
580 // Send wave data to buffer, fill remainder of free space with silence
581 uint num_bytes_written;
582
583 if (WriteWaveData (dwFreeSpace, &num_bytes_written) == true) {
584 // nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));
585
586 if ( m_total_uncompressed_bytes_read >= m_max_uncompressed_bytes_to_read ) {
587 m_fade_timer_id = timer_get_milliseconds() + 1700; // start fading 1.7 seconds from now
588 m_finished_id = timer_get_milliseconds() + 2000; // 2 seconds left to play out buffer
589 m_max_uncompressed_bytes_to_read = std::numeric_limits<uint>::max();
590 }
591
592 if ( (m_fade_timer_id>0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
593 m_fade_timer_id = 0;
594 Fade_and_Stop();
595 }
596
597 if ( (m_finished_id>0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
598 m_finished_id = 0;
599 m_bPastLimit = true;
600 }
601
602 if ( PlaybackDone() ) {
603 if ( m_bDestroy_when_faded == true ) {
604 SDL_UnlockMutex( write_lock );
605
606 Destroy();
607 // Reset reentrancy semaphore
608
609 return false;
610 }
611 // All of sound has played, stop playback or loop again
612 if ( m_bLooping && !m_bFade) {
613 Play(m_lVolume, m_bLooping);
614 } else {
615 Stop_and_Rewind();
616 }
617 }
618 }
619 else {
620 // Error writing wave data
621 fRtn = false;
622 Int3();
623 }
624 }
625
626 SDL_UnlockMutex( write_lock );
627
628 return (fRtn);
629 }
630
631 // Cue
Cue(void)632 void AudioStream::Cue (void)
633 {
634 uint num_bytes_written;
635
636 if (!m_fCued) {
637 m_bFade = false;
638 m_fade_timer_id = 0;
639 m_finished_id = 0;
640 m_bPastLimit = false;
641 m_lVolume = 1.0f;
642 m_lCutoffVolume = 0.0f;
643
644 m_bDestroy_when_faded = false;
645
646 // Reset buffer ptr
647 m_cbBufOffset = 0;
648
649 // Reset file ptr, etc
650 m_pwavefile->Cue ();
651
652 // Unqueue all buffers
653 ALint buffers_processed = 0;
654 OpenAL_ErrorPrint( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed) );
655
656 while (buffers_processed) {
657 ALuint buffer_id = 0;
658 OpenAL_ErrorPrint( alSourceUnqueueBuffers(m_source_id, 1, &buffer_id) );
659 buffers_processed--;
660 }
661
662 // Fill buffer with wave data
663 WriteWaveData (m_cbBufSize, &num_bytes_written, 0);
664
665 m_fCued = true;
666
667 // Init some of our data
668 m_total_uncompressed_bytes_read = 0;
669 m_max_uncompressed_bytes_to_read = std::numeric_limits<uint>::max();
670 }
671 }
672
673 // Play
Play(float volume,int looping)674 void AudioStream::Play (float volume, int looping)
675 {
676 if (m_buffer_ids[0] != 0) {
677 // If playing, stop
678 if (m_fPlaying) {
679 if ( m_bIsPaused == false)
680 Stop_and_Rewind();
681 }
682
683 // loop flag must be set before Cue()!
684 if ( looping )
685 m_bLooping = 1;
686 else
687 m_bLooping = 0;
688
689 // Cue for playback if necessary
690 if ( !m_fCued )
691 Cue ();
692
693 OpenAL_ErrorPrint( alSourcePlay(m_source_id) );
694
695 m_nTimeStarted = timer_get_milliseconds();
696 Set_Volume(volume);
697
698 // Kick off timer to service buffer
699 m_timer.constructor();
700
701 m_timer.Create (m_nBufService, m_nBufService, ptr_u (this), TimerCallback);
702
703 // Playback begun, no longer cued
704 m_fPlaying = true;
705 m_bIsPaused = false;
706 }
707 }
708
709 // Timer callback for Timer object created by ::Play method.
TimerCallback(ptr_u dwUser)710 bool AudioStream::TimerCallback (ptr_u dwUser)
711 {
712 // dwUser contains ptr to AudioStream object
713 AudioStream * pas = (AudioStream *) dwUser;
714
715 return (pas->ServiceBuffer ());
716 }
717
Set_Sample_Cutoff(unsigned int sample_cutoff)718 void AudioStream::Set_Sample_Cutoff(unsigned int sample_cutoff)
719 {
720 if ( m_pwavefile == NULL )
721 return;
722
723 m_max_uncompressed_bytes_to_read = (sample_cutoff * m_fileProps.bytes_per_sample);
724 }
725
Get_Samples_Committed(void)726 uint AudioStream::Get_Samples_Committed(void)
727 {
728 if ( m_pwavefile == NULL )
729 return 0;
730
731 return (uint) (m_total_uncompressed_bytes_read / m_fileProps.bytes_per_sample);
732 }
733
734
735 /** Have stream fade out and be destroyed when inaudabile.
736 If stream is already done or never started just destroy it now.
737 */
Fade_and_Destroy(void)738 void AudioStream::Fade_and_Destroy (void)
739 {
740 if (!m_fPlaying || PlaybackDone())
741 {
742 Destroy();
743 }
744 else
745 {
746 m_bFade = true;
747 m_bDestroy_when_faded = true;
748 }
749 }
750
751 // Fade_and_Destroy
Fade_and_Stop(void)752 void AudioStream::Fade_and_Stop (void)
753 {
754 m_bFade = true;
755 m_bDestroy_when_faded = false;
756 }
757
758
759 // Stop
Stop(int paused)760 void AudioStream::Stop(int paused)
761 {
762 if (m_fPlaying) {
763 if (paused) {
764 OpenAL_ErrorPrint( alSourcePause(m_source_id) );
765 } else {
766 OpenAL_ErrorPrint( alSourceStop(m_source_id) );
767 }
768
769 m_fPlaying = false;
770 m_bIsPaused = (paused != 0);
771
772 // Delete Timer object
773 m_timer.destructor();
774 }
775 }
776
777 // Stop_and_Rewind
Stop_and_Rewind(void)778 void AudioStream::Stop_and_Rewind (void)
779 {
780 if (m_fPlaying) {
781 // Stop playback
782 OpenAL_ErrorPrint( alSourceStop(m_source_id) );
783
784 // Delete Timer object
785 m_timer.destructor();
786
787 m_fPlaying = false;
788 m_bIsPaused = false;
789 }
790
791 // Unqueue all buffers
792 ALint buffers_processed = 0;
793 OpenAL_ErrorPrint( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed) );
794
795 while (buffers_processed) {
796 ALuint buffer_id = 0;
797 OpenAL_ErrorPrint( alSourceUnqueueBuffers(m_source_id, 1, &buffer_id) );
798 buffers_processed--;
799 }
800
801 m_fCued = false; // this will cause wave file to start from beginning
802 m_bReadingDone = false;
803 }
804
805 // Set_Volume
Set_Volume(float vol)806 void AudioStream::Set_Volume(float vol)
807 {
808 CAP(vol, 0.0f, 1.0f);
809
810 OpenAL_ErrorPrint( alSourcef(m_source_id, AL_GAIN, vol) );
811
812 m_lVolume = vol;
813 }
814
815
816 // Set_Volume
Get_Volume()817 float AudioStream::Get_Volume()
818 {
819 return m_lVolume;
820 }
821
PlaybackDone()822 bool AudioStream::PlaybackDone()
823 {
824 ALint state = 0;
825 OpenAL_ErrorPrint( alGetSourcei(m_source_id, AL_SOURCE_STATE, &state) );
826
827 if (m_bReadingDone && (state != AL_PLAYING))
828 return true;
829 else
830 return false;
831 }
832
833
834 AudioStream Audio_streams[MAX_AUDIO_STREAMS];
835
836
audiostream_init()837 void audiostream_init()
838 {
839 int i;
840
841 if ( Audiostream_inited == 1 )
842 return;
843
844 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
845 // disk during a load/cue
846 if ( Wavedata_load_buffer == NULL ) {
847 Wavedata_load_buffer = (ubyte*)vm_malloc(BIGBUF_SIZE);
848 Assert(Wavedata_load_buffer != NULL);
849 }
850
851 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
852 // disk during a service interval
853 if ( Wavedata_service_buffer == NULL ) {
854 Wavedata_service_buffer = (ubyte*)vm_malloc(BIGBUF_SIZE);
855 Assert(Wavedata_service_buffer != NULL);
856 }
857
858 // Allocate memory for the buffer which holds the compressed wave data that is read from the hard disk
859 if ( Compressed_buffer == NULL ) {
860 Compressed_buffer = (ubyte*)vm_malloc(COMPRESSED_BUFFER_SIZE);
861 Assert(Compressed_buffer != NULL);
862 }
863
864 if ( Compressed_service_buffer == NULL ) {
865 Compressed_service_buffer = (ubyte*)vm_malloc(COMPRESSED_BUFFER_SIZE);
866 Assert(Compressed_service_buffer != NULL);
867 }
868
869 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
870 Audio_streams[i].Init_Data();
871 Audio_streams[i].status = ASF_FREE;
872 Audio_streams[i].type = ASF_NONE;
873 Audio_streams[i].paused_via_sexp_or_script = false;
874 }
875
876 SDL_InitSubSystem(SDL_INIT_TIMER);
877
878 Global_service_lock = SDL_CreateMutex();
879
880 Audiostream_inited = 1;
881 }
882
883 // Close down the audiostream system. Must call audiostream_init() before any audiostream functions can
884 // be used.
audiostream_close()885 void audiostream_close()
886 {
887 if ( Audiostream_inited == 0 )
888 return;
889
890 int i;
891
892 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
893 if ( Audio_streams[i].status == ASF_USED ) {
894 Audio_streams[i].status = ASF_FREE;
895 Audio_streams[i].Destroy();
896 }
897 }
898
899 // free global buffers
900 if ( Wavedata_load_buffer ) {
901 vm_free(Wavedata_load_buffer);
902 Wavedata_load_buffer = NULL;
903 }
904
905 if ( Wavedata_service_buffer ) {
906 vm_free(Wavedata_service_buffer);
907 Wavedata_service_buffer = NULL;
908 }
909
910 if ( Compressed_buffer ) {
911 vm_free(Compressed_buffer);
912 Compressed_buffer = NULL;
913 }
914
915 if ( Compressed_service_buffer ) {
916 vm_free(Compressed_service_buffer);
917 Compressed_service_buffer = NULL;
918 }
919
920 SDL_DestroyMutex( Global_service_lock );
921
922 Audiostream_inited = 0;
923
924 }
925
audiostream_use_next_free(int type)926 static int audiostream_use_next_free( int type )
927 {
928 if ( !Audiostream_inited || !snd_is_inited() )
929 return -1;
930
931 int i;
932 for (i = 0; i < MAX_AUDIO_STREAMS; i++)
933 if (Audio_streams[i].status == ASF_FREE)
934 break;
935
936 if (i == MAX_AUDIO_STREAMS) {
937 nprintf(("Sound", "SOUND => No more audio streams available!\n"));
938 return -1;
939 }
940
941 Audio_streams[i].status = ASF_USED;
942 Audio_streams[i].type = type;
943
944 switch (type) {
945 case ASF_SOUNDFX: // As in: sound.cpp:590
946 Audio_streams[i].Set_Default_Volume(Master_sound_volume * aav_effect_volume);
947 break;
948 case ASF_EVENTMUSIC: // As in: sexp.cpp:11562
949 Audio_streams[i].Set_Default_Volume(Master_event_music_volume * aav_music_volume);
950 break;
951 case ASF_MENUMUSIC: // As in: mainhallmenu.cpp:1170
952 Audio_streams[i].Set_Default_Volume(Master_event_music_volume);
953 break;
954 case ASF_VOICE: // As in: sound.cpp:590
955 Audio_streams[i].Set_Default_Volume(Master_voice_volume * aav_voice_volume);
956 break;
957 default:
958 Audio_streams[i].status = ASF_FREE;
959 return -1;
960 }
961
962 return i;
963 }
964
965 // Open a digital sound file for streaming
966 //
967 // input: filename => disk filename of sound file
968 // type => what type of audio stream do we want to open:
969 // ASF_SOUNDFX
970 // ASF_EVENTMUSIC
971 // ASF_MENUMUSIC
972 // ASF_VOICE
973 //
974 // returns: success => handle to identify streaming sound
975 // failure => -1
audiostream_open(const char * filename,int type)976 int audiostream_open( const char *filename, int type )
977 {
978 int i = audiostream_use_next_free(type);
979 if ( i == -1 )
980 return -1;
981
982 char fname[MAX_FILENAME_LEN];
983 // copy filename, since we might modify it
984 strcpy_s(fname, filename);
985
986 switch (type)
987 {
988 case ASF_VOICE:
989 case ASF_SOUNDFX:
990 case ASF_MENUMUSIC:
991 {
992 // go ahead and strip off file extension
993 char *p = strrchr(fname, '.');
994 if ( p && (strlen(p) > 2) )
995 (*p) = 0;
996
997 break;
998 }
999
1000 case ASF_EVENTMUSIC:
1001 break;
1002
1003 default:
1004 Audio_streams[i].status = ASF_FREE;
1005 return -1;
1006 }
1007
1008 int rc = Audio_streams[i].Create(fname);
1009
1010 if ( rc == 0 ) {
1011 Audio_streams[i].status = ASF_FREE;
1012 return -1;
1013 } else {
1014 return i;
1015 }
1016 }
1017
1018 // Open wave file contents previously loaded into memory for streaming
1019 //
1020 //input: snddata => reference of an in-memory file
1021 // snd_len => length of loaded file
1022 // type => what type of audio stream do we want to open:
1023 // ASF_SOUNDFX
1024 // ASF_EVENTMUSIC
1025 // ASF_MENUMUSIC
1026 // ASF_VOICE
1027 //
1028 // returns: success => handle to identify streaming sound
1029 // failure => -1
audiostream_open_mem(const uint8_t * snddata,size_t snd_len,int type)1030 int audiostream_open_mem( const uint8_t* snddata, size_t snd_len, int type )
1031 {
1032 int i = audiostream_use_next_free(type);
1033 if ( i == -1 )
1034 return -1;
1035
1036 int rc = Audio_streams[i].CreateMem(snddata, snd_len);
1037
1038 if ( rc == 0 ) {
1039 Audio_streams[i].status = ASF_FREE;
1040 return -1;
1041 } else {
1042 return i;
1043 }
1044 }
1045
audiostream_close_file(int i,bool fade)1046 void audiostream_close_file(int i, bool fade)
1047 {
1048 if (!Audiostream_inited)
1049 return;
1050
1051 if ( i == -1 )
1052 return;
1053
1054 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1055
1056 if ( Audio_streams[i].status == ASF_USED ) {
1057 if ( fade )
1058 Audio_streams[i].Fade_and_Destroy();
1059 else
1060 Audio_streams[i].Destroy();
1061 }
1062
1063 }
1064
audiostream_close_all(bool fade)1065 void audiostream_close_all(bool fade)
1066 {
1067 int i;
1068
1069 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1070 if ( Audio_streams[i].status == ASF_FREE )
1071 continue;
1072
1073 audiostream_close_file(i, fade);
1074 }
1075 }
1076
audiostream_play(int i,float volume,int looping)1077 void audiostream_play(int i, float volume, int looping)
1078 {
1079 if (!Audiostream_inited)
1080 return;
1081
1082 if ( i == -1 )
1083 return;
1084
1085 Assert(looping >= 0);
1086 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1087
1088 if (volume == -1.0f) {
1089 volume = Audio_streams[i].Get_Default_Volume();
1090 }
1091
1092 Assert(volume >= 0.0f && volume <= 1.0f );
1093 CAP(volume, 0.0f, 1.0f);
1094
1095 Assert( Audio_streams[i].status == ASF_USED );
1096 Audio_streams[i].Set_Default_Volume(volume);
1097 Audio_streams[i].Play(volume, looping);
1098 }
1099
1100 // use as buffer service function
audiostream_is_playing(int i)1101 int audiostream_is_playing(int i)
1102 {
1103 if ( i == -1 )
1104 return 0;
1105
1106 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1107
1108 if ( Audio_streams[i].status != ASF_USED )
1109 return 0;
1110
1111 return (int)Audio_streams[i].Is_Playing();
1112 }
1113
audiostream_stop(int i,int rewind,int paused)1114 void audiostream_stop(int i, int rewind, int paused)
1115 {
1116 if (!Audiostream_inited)
1117 return;
1118
1119 if ( i == -1 )
1120 return;
1121
1122 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1123 Assert( Audio_streams[i].status == ASF_USED );
1124
1125 if ( rewind )
1126 Audio_streams[i].Stop_and_Rewind();
1127 else
1128 Audio_streams[i].Stop(paused);
1129 }
1130
audiostream_set_volume_all(float volume,int type)1131 void audiostream_set_volume_all(float volume, int type)
1132 {
1133 int i;
1134
1135 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1136 if ( Audio_streams[i].status == ASF_FREE )
1137 continue;
1138
1139 if ( (Audio_streams[i].type == type) || ((Audio_streams[i].type == ASF_MENUMUSIC) && (type == ASF_EVENTMUSIC)) ) {
1140 Audio_streams[i].Set_Volume(volume);
1141 }
1142 }
1143 }
1144
audiostream_set_volume(int i,float volume)1145 void audiostream_set_volume(int i, float volume)
1146 {
1147 if ( i == -1 )
1148 return;
1149
1150 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1151 Assert( volume >= 0.0f && volume <= 1.0f);
1152
1153 if ( Audio_streams[i].status == ASF_FREE )
1154 return;
1155
1156 Audio_streams[i].Set_Volume(volume);
1157 }
1158
audiostream_is_paused(int i)1159 int audiostream_is_paused(int i)
1160 {
1161 if ( i == -1 )
1162 return 0;
1163
1164 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1165
1166 if ( Audio_streams[i].status == ASF_FREE )
1167 return -1;
1168
1169 return (int) Audio_streams[i].Is_Paused();
1170 }
1171
audiostream_set_sample_cutoff(int i,uint cutoff)1172 void audiostream_set_sample_cutoff(int i, uint cutoff)
1173 {
1174 if ( i == -1 )
1175 return;
1176
1177 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1178 Assert( cutoff > 0 );
1179
1180 if ( Audio_streams[i].status == ASF_FREE )
1181 return;
1182
1183 Audio_streams[i].Set_Sample_Cutoff(cutoff);
1184 }
1185
audiostream_get_samples_committed(int i)1186 uint audiostream_get_samples_committed(int i)
1187 {
1188 if ( i == -1 )
1189 return 0;
1190
1191 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1192
1193 if ( Audio_streams[i].status == ASF_FREE )
1194 return 0;
1195
1196 return Audio_streams[i].Get_Samples_Committed();
1197 }
1198
audiostream_done_reading(int i)1199 int audiostream_done_reading(int i)
1200 {
1201 if ( i == -1 )
1202 return 0;
1203
1204 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1205
1206 if ( Audio_streams[i].status == ASF_FREE )
1207 return 0;
1208
1209 return Audio_streams[i].Is_Past_Limit();
1210 }
1211
audiostream_is_inited()1212 int audiostream_is_inited()
1213 {
1214 return Audiostream_inited;
1215 }
1216
audiostream_pause(int i,bool via_sexp_or_script)1217 void audiostream_pause(int i, bool via_sexp_or_script)
1218 {
1219 if ( i == -1 )
1220 return;
1221
1222 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1223
1224 if ( Audio_streams[i].status == ASF_FREE )
1225 return;
1226
1227 if ( audiostream_is_playing(i) == (int)true )
1228 audiostream_stop(i, 0, 1);
1229
1230 if (via_sexp_or_script)
1231 Audio_streams[i].paused_via_sexp_or_script = true;
1232 }
1233
audiostream_unpause(int i,bool via_sexp_or_script)1234 void audiostream_unpause(int i, bool via_sexp_or_script)
1235 {
1236 if ( i == -1 )
1237 return;
1238
1239 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1240
1241 if ( Audio_streams[i].status == ASF_FREE )
1242 return;
1243
1244 if ( audiostream_is_paused(i) == (int)true ) {
1245 audiostream_play(i, Audio_streams[i].Get_Volume(), Audio_streams[i].Is_looping());
1246 }
1247
1248 if (via_sexp_or_script)
1249 Audio_streams[i].paused_via_sexp_or_script = false;
1250 }
1251
audiostream_pause_all(bool via_sexp_or_script)1252 void audiostream_pause_all(bool via_sexp_or_script)
1253 {
1254 int i;
1255
1256 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1257 if ( Audio_streams[i].status == ASF_FREE )
1258 continue;
1259
1260 audiostream_pause(i, via_sexp_or_script);
1261 }
1262 }
1263
audiostream_unpause_all(bool via_sexp_or_script)1264 void audiostream_unpause_all(bool via_sexp_or_script)
1265 {
1266 int i;
1267
1268 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1269 if ( Audio_streams[i].status == ASF_FREE )
1270 continue;
1271
1272 // if we explicitly paused this and we are not explicitly unpausing, skip this stream
1273 if ( Audio_streams[i].paused_via_sexp_or_script && !via_sexp_or_script )
1274 continue;
1275
1276 audiostream_unpause(i, via_sexp_or_script);
1277 }
1278 }
1279