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