7 * OpenAL based audio streaming
10 * Revision 1.4 2005/10/01 21:53:06 taylor
11 * include file cleanup
12 * byte-swap streaming PCM to avoid the endless, loud, static
14 * Revision 1.3 2005/08/13 16:59:23 taylor
17 * Revision 1.2 2005/08/12 20:21:06 taylor
20 * Revision 1.1 2005/08/12 08:44:39 taylor
21 * import of FS2_Open audio code which is now *nix only, does not include windows or ogg support that FS2_Open has
23 * Revision 1.12 2005/06/24 19:36:49 taylor
24 * we only want to have m_data_offset be 0 for oggs since the seeking callback will account for the true offset
25 * only extern the one int we need for the -nosound speech fix rather than including the entire header
27 * Revision 1.11 2005/06/19 02:45:55 taylor
28 * OGG streaming fixes to get data reading right and avoid skipping
29 * properly handle seeking in OGG streams
30 * compiler warning fix in OpenAL builds
32 * Revision 1.10 2005/06/01 09:41:14 taylor
33 * bit of cleanup for audiostr-openal and fix a Windows-only enum error
34 * bunch of OGG related fixes for Linux and Windows (DirectSound and OpenAL), fixes audio related TBP 3.2 crashes
35 * gracefully handle OGG logical bitstream changes, shouldn't even load if there is more than 1
37 * Revision 1.9 2005/05/28 19:43:28 taylor
38 * debug message fixing
39 * a little bit of code clarity
41 * Revision 1.8 2005/05/24 03:11:38 taylor
42 * an extra bounds check in sound.cpp
43 * fix audiostr error when filename is !NULL but 0 in len might hit on SDL debug code
45 * Revision 1.7 2005/05/15 06:47:57 taylor
46 * don't let the ogg callbacks close the file handle on us, let us do it ourselves to keep things straight
48 * Revision 1.6 2005/05/13 23:09:28 taylor
49 * Ooops! Added the wrong version of the streaming patch from Jens
51 * Revision 1.5 2005/05/12 17:47:57 taylor
52 * use vm_malloc(), vm_free(), vm_realloc(), vm_strdup() rather than system named macros
53 * fixes various problems and is past time to make the switch
54 * fix a few streaming errors in OpenAL code (Jens Granseuer)
55 * temporary change to help deal with missing music in OpenAL Windows builds
56 * don't assert when si->data is NULL unless we really need to check (OpenAL only)
58 * Revision 1.4 2005/04/05 11:48:22 taylor
59 * remove acm-unix.cpp, replaced by acm-openal.cpp since it's properly cross-platform now
60 * better error handling for OpenAL functions
61 * Windows can now build properly with OpenAL
62 * extra check to make sure we don't try and use too many hardware bases sources
63 * fix memory error from OpenAL extension list in certain instances
65 * Revision 1.3 2005/04/01 07:33:08 taylor
66 * fix hanging on exit with OpenAL
67 * some better error handling on OpenAL init and make it more Windows friendly too
68 * basic 3d sound stuff for OpenAL, not working right yet
70 * Revision 1.2 2005/03/27 08:51:24 taylor
71 * this is what coding on an empty stomach will get you
73 * Revision 1.1 2005/03/27 05:48:58 taylor
74 * initial import of OpenAL streaming (many thanks to Pierre Willenbrock for the missing parts)
92 #define MAX_STREAM_BUFFERS 4
95 #define BIGBUF_SIZE 180000 // This can be reduced to 88200 once we don't use any stereo
96 //#define BIGBUF_SIZE 88300 // This can be reduced to 88200 once we don't use any stereo
97 static ubyte *Wavedata_load_buffer = NULL; // buffer used for cueing audiostreams
98 static ubyte *Wavedata_service_buffer = NULL; // buffer used for servicing audiostreams
100 CRITICAL_SECTION Global_service_lock;
102 typedef bool (*TIMERCALLBACK)(ptr_u);
104 #define COMPRESSED_BUFFER_SIZE 88300
105 static ubyte *Compressed_buffer = NULL; // Used to load in compressed data during a cueing interval
106 static ubyte *Compressed_service_buffer = NULL; // Used to read in compressed data during a service interval
108 #define AS_HIGHEST_MAX 999999999 // max uncompressed filesize supported is 999 meg
111 static int Audiostream_inited = 0;
120 bool Create(uint nPeriod, ptr_u dwUser, TIMERCALLBACK pfnCallback);
123 static Uint32 TimeProc(Uint32 interval, void *dwUser);
125 TIMERCALLBACK m_pfnCallback;
128 SDL_TimerID m_nIDTimer;
136 bool Open(const char *pszFilename);
138 int Read(ubyte *pbDest, uint cbSize, int service = 1);
139 ubyte GetSilenceData();
141 uint GetNumBytesRemaining()
143 return (m_nDataSize - m_nBytesPlayed);
146 uint GetUncompressedAvgDataRate()
148 return m_nUncompressedAvgDataRate;
156 uint GetNumBytesPlayed()
158 return m_nBytesPlayed;
161 ALenum GetOALFormat()
166 WAVE_chunk m_wfmt; // format of wave file
167 WAVE_chunk *m_pwfmt_original; // foramt of wave file from actual wave source
168 uint m_total_uncompressed_bytes_read;
169 uint m_max_uncompressed_bytes_to_read;
170 uint m_bits_per_sample_uncompressed;
173 uint m_data_offset; // number of bytes to actual wave data
174 int m_data_bytes_left;
178 uint m_wave_format; // format of wave source (ie WAVE_FORMAT_PCM, WAVE_FORMAT_ADPCM)
179 uint m_nBlockAlign; // wave data block alignment spec
180 uint m_nUncompressedAvgDataRate; // average wave data rate
181 uint m_nDataSize; // size of data chunk
182 uint m_nBytesPlayed; // offset into data chunk
183 bool m_abort_next_read;
187 WAVE_chunk m_wfxDest;
196 bool Create(const char *pszFilename);
198 void Play(float volume, int looping);
199 void Stop(int paused = 0);
200 void Stop_and_Rewind();
201 void Fade_and_Destroy();
202 void Fade_and_Stop();
203 void Set_Volume(float vol);
205 void Set_Byte_Cutoff(uint num_bytes_cutoff);
206 uint Get_Bytes_Committed();
223 void Set_Default_Volume(float _volume)
225 m_lDefaultVolume = _volume;
228 float Get_Default_Volume()
230 return m_lDefaultVolume;
239 ushort m_bits_per_sample_uncompressed;
243 bool WriteWaveData(uint cbSize, uint* num_bytes_written,int service=1);
244 uint GetMaxWriteSize();
245 bool ServiceBuffer();
246 static bool TimerCallback(ptr_u dwUser);
248 ALuint m_source_id; // name of openAL source
249 ALuint m_buffer_ids[MAX_STREAM_BUFFERS]; //names of buffers
250 int m_play_buffer_id;
252 Timer m_timer; // ptr to Timer object
253 WaveFile *m_pwavefile; // ptr to WaveFile object
254 bool m_fCued; // semaphore (stream cued)
255 bool m_fPlaying; // semaphore (stream playing)
256 long m_lInService; // reentrancy semaphore
257 uint m_cbBufOffset; // last write position
258 uint m_nBufLength; // length of sound buffer in msec
259 uint m_cbBufSize; // size of sound buffer in bytes
260 uint m_nBufService; // service interval in msec
261 uint m_nTimeStarted; // time (in system time) playback started
263 bool m_bLooping; // whether or not to loop playback
264 bool m_bFade; // fade out music
265 bool m_bDestroy_when_faded;
266 float m_lVolume; // volume of stream ( 0 -> -10 000 )
267 float m_lCutoffVolume;
268 bool m_bIsPaused; // stream is stopped, but not rewinded
269 ushort m_silence_written; // number of bytes of silence written to buffer
270 ushort m_bReadingDone; // no more bytes to be read from disk, still have remaining buffer to play
271 uint m_fade_timer_id; // timestamp so we know when to start fade
272 uint m_finished_id; // timestamp so we know when we've played #bytes required
273 bool m_bPastLimit; // flag to show we've played past the number of bytes requred
274 float m_lDefaultVolume;
278 // Timer class implementation
280 ////////////////////////////////////////////////////////////
282 void Timer::constructor()
287 void Timer::destructor()
290 SDL_RemoveTimer(m_nIDTimer);
295 bool Timer::Create(uint nPeriod, ptr_u dwUser, TIMERCALLBACK pfnCallback)
297 SDL_assert( pfnCallback != NULL );
298 SDL_assert( nPeriod > 10 );
302 m_pfnCallback = pfnCallback;
304 m_nIDTimer = SDL_AddTimer(m_nPeriod, TimeProc, (void*)this);
307 nprintf(("SOUND", "SOUND ==> Error, unable to create timer\n"));
314 // Calls procedure specified when Timer object was created. The
315 // dwUser parameter contains "this" pointer for associated Timer object.
317 Uint32 Timer::TimeProc(Uint32 interval, void *dwUser)
319 // dwUser contains ptr to Timer object
320 Timer *ptimer = (Timer *)dwUser;
322 // Call user-specified callback and pass back user specified data
323 (ptimer->m_pfnCallback)(ptimer->m_dwUser);
325 if (ptimer->m_nPeriod) {
328 SDL_RemoveTimer(ptimer->m_nIDTimer);
329 ptimer->m_nIDTimer = 0;
336 // WaveFile class implementation
338 ////////////////////////////////////////////////////////////
340 void WaveFile::Init()
345 m_pwfmt_original = NULL;
347 m_nUncompressedAvgDataRate = 0;
350 m_total_uncompressed_bytes_read = 0;
351 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
354 m_abort_next_read = false;
357 void WaveFile::Close()
360 if (m_pwfmt_original) {
361 free(m_pwfmt_original);
362 m_pwfmt_original = NULL;
365 if (m_hStream_open) {
366 ACM_stream_close((void*)m_hStream);
377 bool WaveFile::Open(const char *pszFilename)
380 bool fRtn = true; // assume success
382 uint tag = 0, size = 0, next_chunk;
384 m_total_uncompressed_bytes_read = 0;
385 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
387 m_pwfmt_original = (WAVE_chunk*) malloc (sizeof(WAVE_chunk));
389 if (m_pwfmt_original == NULL) {
393 cfp = cfopen(pszFilename, "rb");
399 // check for valid file type
400 id = cfread_int(cfp);
403 if (id != 0x46464952) {
404 nprintf(("Error", "Not a WAVE file '%s'\n", pszFilename));
411 // check for valid RIFF type
412 id = cfread_int(cfp);
415 if (id != 0x45564157) {
416 nprintf(("Error", "Not a WAVE file '%s'\n", pszFilename));
421 tag = cfread_uint(cfp);
422 size = cfread_uint(cfp);
424 next_chunk = cftell(cfp) + size;
429 m_pwfmt_original->code = cfread_short(cfp);
430 m_pwfmt_original->num_channels = cfread_ushort(cfp);
431 m_pwfmt_original->sample_rate = cfread_uint(cfp);
432 m_pwfmt_original->bytes_per_second = cfread_uint(cfp);
433 m_pwfmt_original->block_align = cfread_ushort(cfp);
434 m_pwfmt_original->bits_per_sample = cfread_ushort(cfp);
436 if (m_pwfmt_original->code != 1) {
437 m_pwfmt_original->extra_size = cfread_ushort(cfp);
440 if (m_pwfmt_original->extra_size) {
441 m_pwfmt_original->extra_data = (ubyte*) malloc (m_pwfmt_original->extra_size);
442 SDL_assert( m_pwfmt_original->extra_data != NULL );
444 if (m_pwfmt_original->extra_data == NULL) {
448 cfread(m_pwfmt_original->extra_data, m_pwfmt_original->extra_size, 1, cfp);
456 m_nDataSize = size; // size of data, compressed size if ADPCM
457 m_data_bytes_left = size;
458 m_data_offset = cftell(cfp);
465 // drop everything else
470 cfseek(cfp, next_chunk, CF_SEEK_SET);
473 // we force PCM format, so keep track of original format for later
474 switch (m_pwfmt_original->code) {
475 case WAVE_FORMAT_PCM:
476 m_wave_format = WAVE_FORMAT_PCM;
477 m_wfmt.bits_per_sample = m_pwfmt_original->bits_per_sample;
480 case WAVE_FORMAT_ADPCM:
481 m_wave_format = WAVE_FORMAT_ADPCM;
482 m_wfmt.bits_per_sample = 16;
483 m_bits_per_sample_uncompressed = 16;
487 nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n", m_pwfmt_original->code));
494 m_wfmt.code = WAVE_FORMAT_PCM;
495 m_wfmt.num_channels = m_pwfmt_original->num_channels;
496 m_wfmt.sample_rate = m_pwfmt_original->sample_rate;
497 m_wfmt.extra_size = 0;
498 m_wfmt.block_align = (ushort)(( m_wfmt.num_channels * m_wfmt.bits_per_sample ) / 8);
499 m_wfmt.bytes_per_second = m_wfmt.block_align * m_wfmt.sample_rate;
502 m_oal_format = AL_FORMAT_MONO8;
504 if (m_wfmt.num_channels == 1) {
505 if (m_wfmt.bits_per_sample == 8) {
506 m_oal_format = AL_FORMAT_MONO8;
507 } else if (m_wfmt.bits_per_sample == 16) {
508 m_oal_format = AL_FORMAT_MONO16;
510 } else if (m_wfmt.num_channels == 2) {
511 if (m_wfmt.bits_per_sample == 8) {
512 m_oal_format = AL_FORMAT_STEREO8;
513 } else if (m_wfmt.bits_per_sample == 16) {
514 m_oal_format = AL_FORMAT_STEREO16;
518 // Init some member data from format chunk
519 m_nBlockAlign = m_pwfmt_original->block_align;
520 m_nUncompressedAvgDataRate = m_wfmt.bytes_per_second;
526 // Handle all errors here
527 nprintf(("SOUND","SOUND ==> Could not open wave file %s for streaming\n", pszFilename));
531 if (m_pwfmt_original) {
532 free(m_pwfmt_original);
533 m_pwfmt_original = NULL;
547 // Set the file pointer to the start of wave data
551 bool fRtn = true; // assume success
554 m_total_uncompressed_bytes_read = 0;
555 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
557 rval = cfseek(cfp, m_data_offset, CF_SEEK_SET);
563 m_data_bytes_left = m_nDataSize;
564 m_abort_next_read = false;
571 // Returns number of bytes actually read.
573 // Returns -1 if there is nothing more to be read. This function can return 0, since
574 // sometimes the amount of bytes requested is too small for the ACM decompression to
575 // locate a suitable block
576 int WaveFile::Read(ubyte *pbDest, uint cbSize, int service)
578 void *dest_buf = NULL, *uncompressed_wave_data;
579 int rc, uncompressed_bytes_written;
580 uint src_bytes_used, convert_len, num_bytes_desired=0, num_bytes_read;
582 // nprintf(("Alan","Reqeusted: %d\n", cbSize));
585 uncompressed_wave_data = Wavedata_service_buffer;
587 uncompressed_wave_data = Wavedata_load_buffer;
590 switch (m_wave_format) {
591 case WAVE_FORMAT_PCM: {
592 num_bytes_desired = cbSize;
598 case WAVE_FORMAT_ADPCM: {
599 if ( !m_hStream_open ) {
600 if ( !ACM_stream_open(m_pwfmt_original, &m_wfxDest, (void**)&m_hStream, m_bits_per_sample_uncompressed) ) {
607 num_bytes_desired = cbSize;
610 dest_buf = Compressed_service_buffer;
612 dest_buf = Compressed_buffer;
615 if (num_bytes_desired <= 0) {
616 num_bytes_desired = 0;
617 // nprintf(("Alan","No bytes required for ADPCM time interval\n"));
619 num_bytes_desired = ACM_query_source_size((void*)m_hStream, cbSize);
620 // nprintf(("Alan","Num bytes desired: %d\n", num_bytes_desired));
627 nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n"));
637 // read data from disk
638 if (m_data_bytes_left <= 0) {
640 uncompressed_bytes_written = 0;
645 if ( (m_data_bytes_left > 0) && (num_bytes_desired > 0) ) {
648 if (num_bytes_desired <= (uint)m_data_bytes_left) {
649 num_bytes_read = num_bytes_desired;
651 num_bytes_read = m_data_bytes_left;
654 actual_read = cfread(dest_buf, 1, num_bytes_read, cfp);
656 if ( (actual_read <= 0) || (m_abort_next_read) ) {
658 uncompressed_bytes_written = 0;
663 if (num_bytes_desired >= (uint)m_data_bytes_left) {
664 m_abort_next_read = 1;
667 num_bytes_read = actual_read;
670 // convert data if necessary, to PCM
671 if (m_wave_format == WAVE_FORMAT_ADPCM) {
672 if ( num_bytes_read > 0 ) {
673 rc = ACM_convert((void*)m_hStream, (ubyte*)dest_buf, num_bytes_read, (ubyte*)uncompressed_wave_data, BIGBUF_SIZE, &convert_len, &src_bytes_used);
679 if (convert_len == 0) {
684 SDL_assert( src_bytes_used <= num_bytes_read );
686 if (src_bytes_used < num_bytes_read) {
687 // seek back file pointer to reposition before unused source data
688 cfseek(cfp, src_bytes_used - num_bytes_read, CF_SEEK_CUR);
691 // Adjust number of bytes left
692 m_data_bytes_left -= src_bytes_used;
693 m_nBytesPlayed += src_bytes_used;
694 uncompressed_bytes_written = convert_len;
696 // Successful read, keep running total of number of data bytes read
699 // Successful read, keep running total of number of data bytes read
700 // Adjust number of bytes left
701 m_data_bytes_left -= num_bytes_read;
702 m_nBytesPlayed += num_bytes_read;
703 uncompressed_bytes_written = num_bytes_read;
705 #if BYTE_ORDER == BIG_ENDIAN
706 if (m_wave_format == WAVE_FORMAT_PCM) {
707 // swap 16-bit sound data
708 if (m_wfmt.bits_per_sample == 16) {
711 for (int i = 0; i < uncompressed_bytes_written; i = (i+2)) {
712 swap_tmp = (ushort*)((ubyte*)dest_buf + i);
713 *swap_tmp = INTEL_SHORT(*swap_tmp);
724 uncompressed_bytes_written = 0;
727 m_total_uncompressed_bytes_read += uncompressed_bytes_written;
728 // nprintf(("Alan","Read: %d\n", uncompressed_bytes_written));
730 return uncompressed_bytes_written;
735 // Returns 8 bits of data representing silence for the Wave file format.
737 // Since we are dealing only with PCM format, we can fudge a bit and take
738 // advantage of the fact that for all PCM formats, silence can be represented
739 // by a single byte, repeated to make up the proper word size. The actual size
740 // of a word of wave data depends on the format:
742 // PCM Format Word Size Silence Data
743 // 8-bit mono 1 byte 0x80
744 // 8-bit stereo 2 bytes 0x8080
745 // 16-bit mono 2 bytes 0x0000
746 // 16-bit stereo 4 bytes 0x00000000
748 ubyte WaveFile::GetSilenceData()
750 ubyte bSilenceData = 0;
752 // Silence data depends on format of Wave file
753 if (m_pwfmt_original) {
754 if (m_wfmt.bits_per_sample == 8) {
755 // For 8-bit formats (unsigned, 0 to 255)
756 // Packed DWORD = 0x80808080;
758 } else if (m_wfmt.bits_per_sample == 16) {
759 // For 16-bit formats (signed, -32768 to 32767)
760 // Packed DWORD = 0x00000000;
773 // AudioStream class implementation
775 ////////////////////////////////////////////////////////////
777 // The following constants are the defaults for our streaming buffer operation.
778 static const ushort DefBufferLength = 2000; // default buffer length in msec
779 static const ushort DefBufferServiceInterval = 250; // default buffer service interval in msec
782 AudioStream::AudioStream()
790 m_bPastLimit = false;
792 m_bDestroy_when_faded = false;
793 m_lDefaultVolume = 1.0f;
795 m_lCutoffVolume = 0.0f;
797 m_silence_written = 0;
798 m_bReadingDone = false;
801 m_bits_per_sample_uncompressed = 0;
803 m_fPlaying = m_fCued = false;
804 m_lInService = false;
806 m_nBufLength = DefBufferLength;
808 m_nBufService = DefBufferServiceInterval;
811 memset(m_buffer_ids, 0, sizeof(m_buffer_ids));
813 m_play_buffer_id = 0;
817 AudioStream::~AudioStream()
822 bool AudioStream::Create(const char *pszFilename)
824 SDL_assert( pszFilename != NULL );
826 if (pszFilename == NULL) {
830 // make 100% sure we got a good filename
831 if ( !strlen(pszFilename) )
834 // Create a new WaveFile object
835 m_pwavefile = (WaveFile *)malloc(sizeof(WaveFile));
836 SDL_assert( m_pwavefile != NULL );
838 if (m_pwavefile == NULL) {
839 nprintf(("Sound", "SOUND => Failed to create WaveFile object %s\n\r", pszFilename));
846 m_pwavefile->m_bits_per_sample_uncompressed = m_bits_per_sample_uncompressed;
849 if ( m_pwavefile->Open(pszFilename) ) {
850 // Calculate sound buffer size in bytes
851 // Buffer size is average data rate times length of buffer
852 // No need for buffer to be larger than wave data though
853 m_cbBufSize = (m_nBufLength/1000) * (m_pwavefile->m_wfmt.bits_per_sample/8) * m_pwavefile->m_wfmt.num_channels * m_pwavefile->m_wfmt.sample_rate;
854 m_cbBufSize /= MAX_STREAM_BUFFERS;
855 // if the requested buffer size is too big then cap it
856 m_cbBufSize = (m_cbBufSize > BIGBUF_SIZE) ? BIGBUF_SIZE : m_cbBufSize;
858 // nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
860 // Create sound buffer
861 alGenBuffers(MAX_STREAM_BUFFERS, m_buffer_ids);
863 Snd_sram += m_cbBufSize * MAX_STREAM_BUFFERS;
865 // Error opening file
866 nprintf(("SOUND", "SOUND => Failed to open wave file: %s\n\r", pszFilename));
868 m_pwavefile->Close();
880 bool AudioStream::Destroy()
885 // Release sound buffer
886 alDeleteBuffers(MAX_STREAM_BUFFERS, m_buffer_ids);
888 Snd_sram -= m_cbBufSize;
890 // Delete WaveFile object
892 m_pwavefile->Close();
905 // Writes wave data to sound buffer. This is a helper method used by Create and
906 // ServiceBuffer; it's not exposed to users of the AudioStream class.
907 bool AudioStream::WriteWaveData(uint size, uint *num_bytes_written, int service)
909 ubyte *uncompressed_wave_data;
911 *num_bytes_written = 0;
913 if ( (size == 0) || m_bReadingDone ) {
917 if ( (m_buffer_ids[0] == 0) || !m_pwavefile ) {
922 SDL_LockMutex(Global_service_lock);
926 uncompressed_wave_data = Wavedata_service_buffer;
928 uncompressed_wave_data = Wavedata_load_buffer;
931 int num_bytes_read = 0;
934 for (int ib = 0; ib < MAX_STREAM_BUFFERS; ib++) {
935 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
937 if (num_bytes_read < 0) {
939 } else if (num_bytes_read > 0) {
940 alBufferData(m_buffer_ids[ib], m_pwavefile->GetOALFormat(), uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.sample_rate);
941 alSourceQueueBuffers(m_source_id, 1, &m_buffer_ids[ib]);
943 *num_bytes_written += num_bytes_read;
947 ALint buffers_processed = 0;
948 ALuint buffer_id = 0;
950 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed);
952 while (buffers_processed) {
953 alSourceUnqueueBuffers(m_source_id, 1, &buffer_id);
955 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
957 if (num_bytes_read < 0) {
959 } else if (num_bytes_read > 0) {
960 alBufferData(buffer_id, m_pwavefile->GetOALFormat(), uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.sample_rate);
961 alSourceQueueBuffers(m_source_id, 1, &buffer_id);
963 *num_bytes_written += num_bytes_read;
971 SDL_UnlockMutex(Global_service_lock);
979 // Helper function to calculate max size of sound buffer write operation, i.e. how much
980 // free space there is in buffer.
981 uint AudioStream::GetMaxWriteSize()
983 uint dwMaxSize = m_cbBufSize;
986 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &n);
988 alGetSourcei(m_source_id, AL_BUFFERS_QUEUED, &q);
990 if ( !n && (q >= MAX_STREAM_BUFFERS) ) {
995 // nprintf(("Alan","Max write size: %d\n", dwMaxSize));
999 #define VOLUME_ATTENUATION_BEFORE_CUTOFF 0.03f // 12db
1000 #define VOLUME_ATTENUATION 0.65f
1002 bool AudioStream::ServiceBuffer()
1007 if (type == ASF_NONE) {
1012 if (m_lCutoffVolume == 0.0f) {
1014 // nprintf(("Alan","Volume is: %d\n",vol));
1015 m_lCutoffVolume = vol * VOLUME_ATTENUATION_BEFORE_CUTOFF;
1018 vol = Get_Volume() * VOLUME_ATTENUATION;
1019 // nprintf(("Alan","Volume is now: %d\n",vol));
1022 // nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
1023 // nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
1024 if (vol < m_lCutoffVolume) {
1026 m_lCutoffVolume = 0.0f;
1028 if (m_bDestroy_when_faded) {
1041 // All of sound not played yet, send more data to buffer
1042 uint dwFreeSpace = GetMaxWriteSize();
1044 // Determine free space in sound buffer
1046 // Some wave data remains, but not enough to fill free space
1047 // Send wave data to buffer, fill remainder of free space with silence
1048 uint num_bytes_written;
1050 if ( WriteWaveData(dwFreeSpace, &num_bytes_written) ) {
1051 // nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));
1053 if (m_pwavefile->m_total_uncompressed_bytes_read >= m_pwavefile->m_max_uncompressed_bytes_to_read) {
1054 m_fade_timer_id = timer_get_milliseconds() + 1700; // start fading 1.7 seconds from now
1055 m_finished_id = timer_get_milliseconds() + 2000; // 2 seconds left to play out buffer
1056 m_pwavefile->m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1059 if ( (m_fade_timer_id > 0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
1060 m_fade_timer_id = 0;
1064 if ( (m_finished_id > 0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
1066 m_bPastLimit = true;
1069 // see if we're done
1072 alGetSourcei(m_source_id, AL_SOURCE_STATE, &state);
1074 if ( m_bReadingDone && (state != AL_PLAYING) ) {
1075 if ( m_bDestroy_when_faded == true ) {
1077 // Reset reentrancy semaphore
1082 // All of sound has played, stop playback or loop again
1083 if ( m_bLooping && !m_bFade) {
1084 Play(m_lVolume, m_bLooping);
1090 // Error writing wave data
1100 void AudioStream::Cue()
1102 uint num_bytes_written;
1106 m_fade_timer_id = 0;
1108 m_bPastLimit = false;
1110 m_lCutoffVolume = 0.0f;
1112 m_bDestroy_when_faded = false;
1117 // Reset file ptr, etc
1120 // Unqueue all buffers
1121 ALint buffers_processed = 0;
1122 ALuint buffer_id = 0;
1124 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed);
1126 while (buffers_processed) {
1127 alSourceUnqueueBuffers(m_source_id, 1, &buffer_id);
1129 buffers_processed--;
1132 // Fill buffer with wave data
1133 WriteWaveData(m_cbBufSize, &num_bytes_written, 0);
1140 void AudioStream::Play(float volume, int looping)
1142 if (m_buffer_ids[0] != 0) {
1145 if ( m_bIsPaused == false)
1149 // Cue for playback if necessary
1160 alSourcePlay(m_source_id);
1162 m_nTimeStarted = timer_get_milliseconds();
1165 // Kick off timer to service buffer
1166 m_timer.constructor();
1168 m_timer.Create(m_nBufService, (ptr_u)this, TimerCallback);
1170 // Playback begun, no longer cued
1172 m_bIsPaused = false;
1176 // Timer callback for Timer object created by ::Play method.
1177 bool AudioStream::TimerCallback(ptr_u dwUser)
1179 // dwUser contains ptr to AudioStream object
1180 AudioStream * pas = (AudioStream *) dwUser;
1182 return (pas->ServiceBuffer ());
1185 void AudioStream::Set_Byte_Cutoff(unsigned int byte_cutoff)
1187 if ( m_pwavefile == NULL )
1190 m_pwavefile->m_max_uncompressed_bytes_to_read = byte_cutoff;
1193 uint AudioStream::Get_Bytes_Committed(void)
1195 if (m_pwavefile == NULL) {
1199 return m_pwavefile->m_total_uncompressed_bytes_read;
1204 void AudioStream::Fade_and_Destroy()
1207 m_bDestroy_when_faded = true;
1211 void AudioStream::Fade_and_Stop()
1214 m_bDestroy_when_faded = false;
1219 void AudioStream::Stop(int paused)
1223 alSourcePause(m_source_id);
1225 alSourceStop(m_source_id);
1229 m_bIsPaused = paused;
1231 // Delete Timer object
1232 m_timer.destructor();
1237 void AudioStream::Stop_and_Rewind()
1241 alSourceStop(m_source_id);
1243 // Delete Timer object
1244 m_timer.destructor();
1249 m_fCued = false; // this will cause wave file to start from beginning
1250 m_bReadingDone = false;
1254 void AudioStream::Set_Volume(float vol)
1256 alSourcef(m_source_id, AL_GAIN, vol);
1263 float AudioStream::Get_Volume()
1269 static std::vector<AudioStream> Audio_streams;
1272 void audiostream_init()
1274 if (Audiostream_inited) {
1278 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1279 // disk during a load/cue
1280 if ( Wavedata_load_buffer == NULL ) {
1281 Wavedata_load_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1282 Assert(Wavedata_load_buffer != NULL);
1285 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1286 // disk during a service interval
1287 if ( Wavedata_service_buffer == NULL ) {
1288 Wavedata_service_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1289 Assert(Wavedata_service_buffer != NULL);
1292 // Allocate memory for the buffer which holds the compressed wave data that is read from the hard disk
1293 if ( Compressed_buffer == NULL ) {
1294 Compressed_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1295 Assert(Compressed_buffer != NULL);
1298 if ( Compressed_service_buffer == NULL ) {
1299 Compressed_service_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1300 Assert(Compressed_service_buffer != NULL);
1303 Audio_streams.clear();
1305 SDL_InitSubSystem(SDL_INIT_TIMER);
1307 Global_service_lock = SDL_CreateMutex();
1309 Audiostream_inited = 1;
1312 // Close down the audiostream system. Must call audiostream_init() before any audiostream functions can
1314 void audiostream_close()
1318 if ( !Audiostream_inited ) {
1322 int size = (int)Audio_streams.size();
1324 for (i = 0; i < size; i++) {
1325 if (Audio_streams[i].type == ASF_NONE) {
1329 Audio_streams[i].Destroy();
1332 Audio_streams.clear();
1334 // free global buffers
1335 if ( Wavedata_load_buffer ) {
1336 free(Wavedata_load_buffer);
1337 Wavedata_load_buffer = NULL;
1340 if ( Wavedata_service_buffer ) {
1341 free(Wavedata_service_buffer);
1342 Wavedata_service_buffer = NULL;
1345 if ( Compressed_buffer ) {
1346 free(Compressed_buffer);
1347 Compressed_buffer = NULL;
1350 if ( Compressed_service_buffer ) {
1351 free(Compressed_service_buffer);
1352 Compressed_service_buffer = NULL;
1355 SDL_DestroyMutex( Global_service_lock );
1357 Audiostream_inited = 0;
1361 // Open a digital sound file for streaming
1363 // input: filename => disk filename of sound file
1364 // type => what type of audio stream do we want to open:
1369 // returns: success => handle to identify streaming sound
1371 int audiostream_open( const char *filename, int type )
1375 if ( !Audiostream_inited ) {
1379 int size = (int)Audio_streams.size();
1381 for (i = 0; i < size; i++) {
1382 if (Audio_streams[i].type == ASF_NONE) {
1383 Audio_streams[i].type = type;
1389 AudioStream n_stream;
1390 Audio_streams.push_back(n_stream);
1396 Audio_streams[i].m_bits_per_sample_uncompressed = 8;
1399 case ASF_EVENTMUSIC:
1400 Audio_streams[i].m_bits_per_sample_uncompressed = 16;
1408 if ( !Audio_streams[i].Create(filename) ) {
1409 Audio_streams[i].type = ASF_NONE;
1416 void audiostream_close_file(int i, int fade)
1418 if ( !Audiostream_inited ) {
1422 SDL_assert( i >= 0 );
1423 SDL_assert( i < (int)Audio_streams.size() );
1429 if (Audio_streams[i].type == ASF_NONE) {
1434 Audio_streams[i].Fade_and_Destroy();
1436 Audio_streams[i].Destroy();
1440 void audiostream_close_all(int fade)
1444 if ( !Audiostream_inited ) {
1448 int size = (int)Audio_streams.size();
1450 for (i = 0; i < size; i++) {
1451 if (Audio_streams[i].type == ASF_NONE) {
1455 audiostream_close_file(i, fade);
1459 void audiostream_play(int i, float volume, int looping)
1461 if ( !Audiostream_inited ) {
1465 SDL_assert( i >= 0 );
1466 SDL_assert( i < (int)Audio_streams.size() );
1472 if (Audio_streams[i].type == ASF_NONE) {
1476 if (volume < 0.0f) {
1477 volume = Audio_streams[i].Get_Default_Volume();
1480 Audio_streams[i].Set_Default_Volume(volume);
1481 Audio_streams[i].Play(volume, looping);
1484 // use as buffer service function
1485 bool audiostream_is_playing(int i)
1487 if ( !Audiostream_inited ) {
1491 SDL_assert( i >= 0 );
1492 SDL_assert( i < (int)Audio_streams.size() );
1498 if (Audio_streams[i].type == ASF_NONE) {
1502 return Audio_streams[i].Is_Playing();
1505 void audiostream_stop(int i, int rewind, int paused)
1507 if ( !Audiostream_inited ) {
1511 SDL_assert( i >= 0 );
1512 SDL_assert( i < (int)Audio_streams.size() );
1518 if (Audio_streams[i].type == ASF_NONE) {
1523 Audio_streams[i].Stop_and_Rewind();
1525 Audio_streams[i].Stop(paused);
1529 void audiostream_set_volume_all(float volume, int type)
1533 if ( !Audiostream_inited ) {
1537 int size = (int)Audio_streams.size();
1539 for (i = 0; i < size; i++) {
1540 if (Audio_streams[i].type == ASF_NONE) {
1544 if (Audio_streams[i].type == type) {
1545 Audio_streams[i].Set_Volume(volume);
1550 void audiostream_set_volume(int i, float volume)
1552 if ( !Audiostream_inited ) {
1556 SDL_assert( i >= 0 );
1557 SDL_assert( i < (int)Audio_streams.size() );
1563 if (Audio_streams[i].type == ASF_NONE) {
1567 Audio_streams[i].Set_Volume(volume);
1570 bool audiostream_is_paused(int i)
1572 if ( !Audiostream_inited ) {
1576 SDL_assert( i >= 0 );
1577 SDL_assert( i < (int)Audio_streams.size() );
1583 if (Audio_streams[i].type == ASF_NONE) {
1587 return Audio_streams[i].Is_Paused();
1590 void audiostream_set_byte_cutoff(int i, uint cutoff)
1592 if ( !Audiostream_inited ) {
1596 SDL_assert( i >= 0 );
1597 SDL_assert( i < (int)Audio_streams.size() );
1603 if (Audio_streams[i].type == ASF_NONE) {
1607 Audio_streams[i].Set_Byte_Cutoff(cutoff);
1610 uint audiostream_get_bytes_committed(int i)
1612 if ( !Audiostream_inited ) {
1616 SDL_assert( i >= 0 );
1617 SDL_assert( i < (int)Audio_streams.size() );
1623 if (Audio_streams[i].type == ASF_NONE) {
1627 return Audio_streams[i].Get_Bytes_Committed();
1630 bool audiostream_done_reading(int i)
1632 if ( !Audiostream_inited ) {
1636 SDL_assert( i >= 0 );
1637 SDL_assert( i < (int)Audio_streams.size() );
1643 if (Audio_streams[i].type == ASF_NONE) {
1647 return Audio_streams[i].Is_Past_Limit();
1650 int audiostream_is_inited()
1652 return Audiostream_inited;
1655 void audiostream_pause(int i)
1657 if ( !Audiostream_inited ) {
1661 SDL_assert( i >= 0 );
1662 SDL_assert( i < (int)Audio_streams.size() );
1668 if (Audio_streams[i].type == ASF_NONE) {
1672 if ( audiostream_is_playing(i) ) {
1673 audiostream_stop(i, 0, 1);
1677 void audiostream_pause_all()
1681 if ( !Audiostream_inited ) {
1685 int size = (int)Audio_streams.size();
1687 for (i = 0; i < size; i++) {
1688 if (Audio_streams[i].type == ASF_NONE) {
1692 audiostream_pause(i);
1696 void audiostream_unpause(int i)
1700 if ( !Audiostream_inited ) {
1704 SDL_assert( i >= 0 );
1705 SDL_assert( i < (int)Audio_streams.size() );
1711 if (Audio_streams[i].type == ASF_NONE) {
1715 if ( audiostream_is_paused(i) ) {
1716 is_looping = Audio_streams[i].Is_looping();
1717 audiostream_play(i, -1.0f, is_looping);
1721 void audiostream_unpause_all()
1725 if ( !Audiostream_inited ) {
1729 int size = (int)Audio_streams.size();
1731 for (i = 0; i < size; i++) {
1732 if (Audio_streams[i].type == ASF_NONE) {
1736 audiostream_unpause(i);