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 SDL_mutex *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
114 static int Audiostream_inited = 0;
123 bool Create(uint nPeriod, ptr_u dwUser, TIMERCALLBACK pfnCallback);
126 static Uint32 TimeProc(Uint32 interval, void *dwUser);
128 TIMERCALLBACK m_pfnCallback;
131 SDL_TimerID m_nIDTimer;
139 bool Open(const char *pszFilename);
141 int Read(ubyte *pbDest, uint cbSize, int service = 1);
142 ubyte GetSilenceData();
144 uint GetNumBytesRemaining()
146 return (m_nDataSize - m_nBytesPlayed);
149 uint GetUncompressedAvgDataRate()
151 return m_nUncompressedAvgDataRate;
159 uint GetNumBytesPlayed()
161 return m_nBytesPlayed;
164 ALenum GetOALFormat()
169 WAVE_chunk m_wfmt; // format of wave file
170 WAVE_chunk *m_pwfmt_original; // foramt of wave file from actual wave source
171 uint m_total_uncompressed_bytes_read;
172 uint m_max_uncompressed_bytes_to_read;
173 uint m_bits_per_sample_uncompressed;
176 uint m_data_offset; // number of bytes to actual wave data
177 int m_data_bytes_left;
181 uint m_wave_format; // format of wave source (ie WAVE_FORMAT_PCM, WAVE_FORMAT_ADPCM)
182 uint m_nBlockAlign; // wave data block alignment spec
183 uint m_nUncompressedAvgDataRate; // average wave data rate
184 uint m_nDataSize; // size of data chunk
185 uint m_nBytesPlayed; // offset into data chunk
186 bool m_abort_next_read;
190 WAVE_chunk m_wfxDest;
199 bool Create(const char *pszFilename);
201 void Play(float volume, int looping);
202 void Stop(bool paused = false);
203 void Stop_and_Rewind();
204 void Fade_and_Destroy();
205 void Fade_and_Stop();
206 void Set_Volume(float vol);
209 void Set_Byte_Cutoff(uint num_bytes_cutoff);
210 uint Get_Bytes_Committed();
227 void Set_Default_Volume(float _volume)
229 m_lDefaultVolume = _volume;
232 float Get_Default_Volume()
234 return m_lDefaultVolume;
244 ushort m_bits_per_sample_uncompressed;
248 bool WriteWaveData(uint cbSize, uint* num_bytes_written,int service=1);
249 uint GetMaxWriteSize();
250 bool ServiceBuffer();
251 static bool TimerCallback(ptr_u dwUser);
253 ALuint m_source_id; // name of openAL source
254 ALuint m_buffer_ids[MAX_STREAM_BUFFERS]; //names of buffers
255 int m_play_buffer_id;
257 Timer m_timer; // ptr to Timer object
258 WaveFile *m_pwavefile; // ptr to WaveFile object
259 bool m_fCued; // semaphore (stream cued)
260 bool m_fPlaying; // semaphore (stream playing)
261 long m_lInService; // reentrancy semaphore
262 uint m_cbBufOffset; // last write position
263 uint m_nBufLength; // length of sound buffer in msec
264 uint m_cbBufSize; // size of sound buffer in bytes
265 uint m_nBufService; // service interval in msec
266 uint m_nTimeStarted; // time (in system time) playback started
268 bool m_bLooping; // whether or not to loop playback
269 bool m_bFade; // fade out music
270 bool m_bDestroy_when_faded;
271 float m_lVolume; // volume of stream ( 0 -> -10 000 )
272 float m_lCutoffVolume;
273 bool m_bIsPaused; // stream is stopped, but not rewinded
274 ushort m_silence_written; // number of bytes of silence written to buffer
275 ushort m_bReadingDone; // no more bytes to be read from disk, still have remaining buffer to play
276 uint m_fade_timer_id; // timestamp so we know when to start fade
277 uint m_finished_id; // timestamp so we know when we've played #bytes required
278 bool m_bPastLimit; // flag to show we've played past the number of bytes requred
279 float m_lDefaultVolume;
283 // Timer class implementation
285 ////////////////////////////////////////////////////////////
287 void Timer::constructor()
292 void Timer::destructor()
295 SDL_RemoveTimer(m_nIDTimer);
300 bool Timer::Create(uint nPeriod, ptr_u dwUser, TIMERCALLBACK pfnCallback)
302 SDL_assert( pfnCallback != NULL );
303 SDL_assert( nPeriod > 10 );
307 m_pfnCallback = pfnCallback;
309 m_nIDTimer = SDL_AddTimer(m_nPeriod, TimeProc, (void*)this);
312 nprintf(("SOUND", "SOUND ==> Error, unable to create timer\n"));
319 // Calls procedure specified when Timer object was created. The
320 // dwUser parameter contains "this" pointer for associated Timer object.
322 Uint32 Timer::TimeProc(Uint32 interval, void *dwUser)
324 // dwUser contains ptr to Timer object
325 Timer *ptimer = (Timer *)dwUser;
327 // Call user-specified callback and pass back user specified data
328 (ptimer->m_pfnCallback)(ptimer->m_dwUser);
330 if (ptimer->m_nPeriod) {
333 SDL_RemoveTimer(ptimer->m_nIDTimer);
334 ptimer->m_nIDTimer = 0;
341 // WaveFile class implementation
343 ////////////////////////////////////////////////////////////
345 void WaveFile::Init()
350 m_pwfmt_original = NULL;
352 m_nUncompressedAvgDataRate = 0;
355 m_total_uncompressed_bytes_read = 0;
356 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
361 m_abort_next_read = false;
364 void WaveFile::Close()
367 if (m_pwfmt_original) {
368 if (m_pwfmt_original->extra_data) {
369 free(m_pwfmt_original->extra_data);
372 free(m_pwfmt_original);
373 m_pwfmt_original = NULL;
376 if (m_hStream_open) {
377 ACM_stream_close((void*)m_hStream);
388 bool WaveFile::Open(const char *pszFilename)
391 bool fRtn = true; // assume success
393 uint tag = 0, size = 0, next_chunk;
395 m_total_uncompressed_bytes_read = 0;
396 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
398 m_pwfmt_original = (WAVE_chunk*) malloc (sizeof(WAVE_chunk));
400 if (m_pwfmt_original == NULL) {
404 SDL_zerop(m_pwfmt_original);
406 cfp = cfopen(pszFilename, "rb");
412 // check for valid file type
413 id = cfread_int(cfp);
416 if (id != 0x46464952) {
417 nprintf(("Error", "Not a WAVE file '%s'\n", pszFilename));
424 // check for valid RIFF type
425 id = cfread_int(cfp);
428 if (id != 0x45564157) {
429 nprintf(("Error", "Not a WAVE file '%s'\n", pszFilename));
434 tag = cfread_uint(cfp);
435 size = cfread_uint(cfp);
437 next_chunk = cftell(cfp) + size;
442 m_pwfmt_original->code = cfread_short(cfp);
443 m_pwfmt_original->num_channels = cfread_ushort(cfp);
444 m_pwfmt_original->sample_rate = cfread_uint(cfp);
445 m_pwfmt_original->bytes_per_second = cfread_uint(cfp);
446 m_pwfmt_original->block_align = cfread_ushort(cfp);
447 m_pwfmt_original->bits_per_sample = cfread_ushort(cfp);
449 if (m_pwfmt_original->code != 1) {
450 m_pwfmt_original->extra_size = cfread_ushort(cfp);
453 if (m_pwfmt_original->extra_size) {
454 m_pwfmt_original->extra_data = (ubyte*) malloc (m_pwfmt_original->extra_size);
455 SDL_assert( m_pwfmt_original->extra_data != NULL );
457 if (m_pwfmt_original->extra_data == NULL) {
461 cfread(m_pwfmt_original->extra_data, m_pwfmt_original->extra_size, 1, cfp);
469 m_nDataSize = size; // size of data, compressed size if ADPCM
470 m_data_bytes_left = size;
471 m_data_offset = cftell(cfp);
478 // drop everything else
483 cfseek(cfp, next_chunk, CF_SEEK_SET);
486 // we force PCM format, so keep track of original format for later
487 switch (m_pwfmt_original->code) {
488 case WAVE_FORMAT_PCM:
489 m_wave_format = WAVE_FORMAT_PCM;
490 m_wfmt.bits_per_sample = m_pwfmt_original->bits_per_sample;
493 case WAVE_FORMAT_ADPCM:
494 m_wave_format = WAVE_FORMAT_ADPCM;
495 m_wfmt.bits_per_sample = 16;
496 m_bits_per_sample_uncompressed = 16;
500 nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n", m_pwfmt_original->code));
507 m_wfmt.code = WAVE_FORMAT_PCM;
508 m_wfmt.num_channels = m_pwfmt_original->num_channels;
509 m_wfmt.sample_rate = m_pwfmt_original->sample_rate;
510 m_wfmt.extra_size = 0;
511 m_wfmt.block_align = (ushort)(( m_wfmt.num_channels * m_wfmt.bits_per_sample ) / 8);
512 m_wfmt.bytes_per_second = m_wfmt.block_align * m_wfmt.sample_rate;
515 m_oal_format = AL_FORMAT_MONO8;
517 if (m_wfmt.num_channels == 1) {
518 if (m_wfmt.bits_per_sample == 8) {
519 m_oal_format = AL_FORMAT_MONO8;
520 } else if (m_wfmt.bits_per_sample == 16) {
521 m_oal_format = AL_FORMAT_MONO16;
523 } else if (m_wfmt.num_channels == 2) {
524 if (m_wfmt.bits_per_sample == 8) {
525 m_oal_format = AL_FORMAT_STEREO8;
526 } else if (m_wfmt.bits_per_sample == 16) {
527 m_oal_format = AL_FORMAT_STEREO16;
531 // Init some member data from format chunk
532 m_nBlockAlign = m_pwfmt_original->block_align;
533 m_nUncompressedAvgDataRate = m_wfmt.bytes_per_second;
539 // Handle all errors here
540 nprintf(("SOUND","SOUND ==> Could not open wave file %s for streaming\n", pszFilename));
544 if (m_pwfmt_original) {
545 if (m_pwfmt_original->extra_data) {
546 free(m_pwfmt_original->extra_data);
549 free(m_pwfmt_original);
550 m_pwfmt_original = NULL;
564 // Set the file pointer to the start of wave data
568 bool fRtn = true; // assume success
571 m_total_uncompressed_bytes_read = 0;
572 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
574 rval = cfseek(cfp, m_data_offset, CF_SEEK_SET);
580 m_data_bytes_left = m_nDataSize;
581 m_abort_next_read = false;
588 // Returns number of bytes actually read.
590 // Returns -1 if there is nothing more to be read. This function can return 0, since
591 // sometimes the amount of bytes requested is too small for the ACM decompression to
592 // locate a suitable block
593 int WaveFile::Read(ubyte *pbDest, uint cbSize, int service)
595 void *dest_buf = NULL, *uncompressed_wave_data;
596 int rc, uncompressed_bytes_written;
597 uint src_bytes_used, convert_len, num_bytes_desired=0, num_bytes_read;
599 // nprintf(("Alan","Reqeusted: %d\n", cbSize));
602 uncompressed_wave_data = Wavedata_service_buffer;
604 uncompressed_wave_data = Wavedata_load_buffer;
607 switch (m_wave_format) {
608 case WAVE_FORMAT_PCM: {
609 num_bytes_desired = cbSize;
615 case WAVE_FORMAT_ADPCM: {
616 if ( !m_hStream_open ) {
617 if ( !ACM_stream_open(m_pwfmt_original, &m_wfxDest, (void**)&m_hStream, m_bits_per_sample_uncompressed) ) {
624 num_bytes_desired = cbSize;
627 dest_buf = Compressed_service_buffer;
629 dest_buf = Compressed_buffer;
632 if (num_bytes_desired <= 0) {
633 num_bytes_desired = 0;
634 // nprintf(("Alan","No bytes required for ADPCM time interval\n"));
636 num_bytes_desired = ACM_query_source_size((void*)m_hStream, cbSize);
637 // nprintf(("Alan","Num bytes desired: %d\n", num_bytes_desired));
644 nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n"));
654 // read data from disk
655 if (m_data_bytes_left <= 0) {
659 if ( (m_data_bytes_left > 0) && (num_bytes_desired > 0) ) {
662 if (num_bytes_desired <= (uint)m_data_bytes_left) {
663 num_bytes_read = num_bytes_desired;
665 num_bytes_read = m_data_bytes_left;
668 actual_read = cfread(dest_buf, 1, num_bytes_read, cfp);
670 if ( (actual_read <= 0) || (m_abort_next_read) ) {
674 if (num_bytes_desired >= (uint)m_data_bytes_left) {
675 m_abort_next_read = 1;
678 num_bytes_read = actual_read;
681 // convert data if necessary, to PCM
682 if (m_wave_format == WAVE_FORMAT_ADPCM) {
683 if ( num_bytes_read > 0 ) {
684 rc = ACM_convert((void*)m_hStream, (ubyte*)dest_buf, num_bytes_read, (ubyte*)uncompressed_wave_data, BIGBUF_SIZE, &convert_len, &src_bytes_used);
690 if (convert_len == 0) {
695 SDL_assert( src_bytes_used <= num_bytes_read );
697 if (src_bytes_used < num_bytes_read) {
698 // seek back file pointer to reposition before unused source data
699 cfseek(cfp, src_bytes_used - num_bytes_read, CF_SEEK_CUR);
702 // Adjust number of bytes left
703 m_data_bytes_left -= src_bytes_used;
704 m_nBytesPlayed += src_bytes_used;
705 uncompressed_bytes_written = convert_len;
707 // Successful read, keep running total of number of data bytes read
710 // Successful read, keep running total of number of data bytes read
711 // Adjust number of bytes left
712 m_data_bytes_left -= num_bytes_read;
713 m_nBytesPlayed += num_bytes_read;
714 uncompressed_bytes_written = num_bytes_read;
716 #if BYTE_ORDER == BIG_ENDIAN
717 if (m_wave_format == WAVE_FORMAT_PCM) {
718 // swap 16-bit sound data
719 if (m_wfmt.bits_per_sample == 16) {
722 for (int i = 0; i < uncompressed_bytes_written; i = (i+2)) {
723 swap_tmp = (ushort*)((ubyte*)dest_buf + i);
724 *swap_tmp = INTEL_SHORT(*swap_tmp);
734 uncompressed_bytes_written = 0;
737 m_total_uncompressed_bytes_read += uncompressed_bytes_written;
738 // nprintf(("Alan","Read: %d\n", uncompressed_bytes_written));
740 return uncompressed_bytes_written;
745 // Returns 8 bits of data representing silence for the Wave file format.
747 // Since we are dealing only with PCM format, we can fudge a bit and take
748 // advantage of the fact that for all PCM formats, silence can be represented
749 // by a single byte, repeated to make up the proper word size. The actual size
750 // of a word of wave data depends on the format:
752 // PCM Format Word Size Silence Data
753 // 8-bit mono 1 byte 0x80
754 // 8-bit stereo 2 bytes 0x8080
755 // 16-bit mono 2 bytes 0x0000
756 // 16-bit stereo 4 bytes 0x00000000
758 ubyte WaveFile::GetSilenceData()
760 ubyte bSilenceData = 0;
762 // Silence data depends on format of Wave file
763 if (m_pwfmt_original) {
764 if (m_wfmt.bits_per_sample == 8) {
765 // For 8-bit formats (unsigned, 0 to 255)
766 // Packed DWORD = 0x80808080;
768 } else if (m_wfmt.bits_per_sample == 16) {
769 // For 16-bit formats (signed, -32768 to 32767)
770 // Packed DWORD = 0x00000000;
783 // AudioStream class implementation
785 ////////////////////////////////////////////////////////////
787 // The following constants are the defaults for our streaming buffer operation.
788 static const ushort DefBufferLength = 2000; // default buffer length in msec
789 static const ushort DefBufferServiceInterval = 250; // default buffer service interval in msec
792 AudioStream::AudioStream()
797 AudioStream::~AudioStream()
801 void AudioStream::Init_Data()
807 m_bPastLimit = false;
809 m_bDestroy_when_faded = false;
810 m_lDefaultVolume = 1.0f;
812 m_lCutoffVolume = 0.0f;
814 m_silence_written = 0;
815 m_bReadingDone = false;
819 m_fPlaying = m_fCued = false;
820 m_lInService = false;
822 m_nBufLength = DefBufferLength;
824 m_nBufService = DefBufferServiceInterval;
827 memset(m_buffer_ids, 0, sizeof(m_buffer_ids));
829 m_play_buffer_id = 0;
833 bool AudioStream::Create(const char *pszFilename)
835 SDL_assert( pszFilename != NULL );
839 if (pszFilename == NULL) {
843 // make 100% sure we got a good filename
844 if ( !strlen(pszFilename) ) {
848 // Create a new WaveFile object
849 m_pwavefile = (WaveFile *)malloc(sizeof(WaveFile));
850 SDL_assert( m_pwavefile != NULL );
852 if (m_pwavefile == NULL) {
853 nprintf(("Sound", "SOUND => Failed to create WaveFile object %s\n\r", pszFilename));
860 m_pwavefile->m_bits_per_sample_uncompressed = m_bits_per_sample_uncompressed;
863 if ( m_pwavefile->Open(pszFilename) ) {
864 // Calculate sound buffer size in bytes
865 // Buffer size is average data rate times length of buffer
866 // No need for buffer to be larger than wave data though
867 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;
868 m_cbBufSize /= MAX_STREAM_BUFFERS;
869 // align buffer to format
870 m_cbBufSize += m_cbBufSize % ((m_pwavefile->m_wfmt.bits_per_sample/8) * m_pwavefile->m_wfmt.num_channels);
871 // if the requested buffer size is too big then cap it
872 m_cbBufSize = (m_cbBufSize > BIGBUF_SIZE) ? BIGBUF_SIZE : m_cbBufSize;
874 // nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
876 // Create sound buffer
877 alGenBuffers(MAX_STREAM_BUFFERS, m_buffer_ids);
879 Snd_sram += m_cbBufSize * MAX_STREAM_BUFFERS;
881 // Error opening file
882 nprintf(("SOUND", "SOUND => Failed to open wave file: %s\n\r", pszFilename));
884 m_pwavefile->Close();
896 bool AudioStream::Destroy()
901 // Release sound buffer
902 alDeleteBuffers(MAX_STREAM_BUFFERS, m_buffer_ids);
904 Snd_sram -= m_cbBufSize;
906 // Delete WaveFile object
908 m_pwavefile->Close();
921 // Writes wave data to sound buffer. This is a helper method used by Create and
922 // ServiceBuffer; it's not exposed to users of the AudioStream class.
923 bool AudioStream::WriteWaveData(uint size, uint *num_bytes_written, int service)
925 ubyte *uncompressed_wave_data;
927 *num_bytes_written = 0;
929 if ( (size == 0) || m_bReadingDone ) {
933 if ( (m_buffer_ids[0] == 0) || !m_pwavefile ) {
938 SDL_LockMutex(Global_service_lock);
942 uncompressed_wave_data = Wavedata_service_buffer;
944 uncompressed_wave_data = Wavedata_load_buffer;
947 int num_bytes_read = 0;
949 oal_check_for_errors("AudioStream::WriteWaveData() begin");
952 for (int ib = 0; ib < MAX_STREAM_BUFFERS; ib++) {
953 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
955 // if looping then maybe reset wavefile and keep going
956 if ( (num_bytes_read < 0) && m_bLooping) {
958 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize);
961 if (num_bytes_read < 0) {
964 } else if (num_bytes_read > 0) {
965 alBufferData(m_buffer_ids[ib], m_pwavefile->GetOALFormat(), uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.sample_rate);
966 alSourceQueueBuffers(m_source_id, 1, &m_buffer_ids[ib]);
967 *num_bytes_written += num_bytes_read;
971 ALint buffers_processed = 0;
972 ALuint buffer_id = 0;
974 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed);
976 while (buffers_processed) {
977 alSourceUnqueueBuffers(m_source_id, 1, &buffer_id);
979 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
981 // if looping then maybe reset wavefile and keep going
982 if ( (num_bytes_read < 0) && m_bLooping) {
984 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize);
987 if (num_bytes_read < 0) {
989 } else if (num_bytes_read > 0) {
990 alBufferData(buffer_id, m_pwavefile->GetOALFormat(), uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.sample_rate);
991 alSourceQueueBuffers(m_source_id, 1, &buffer_id);
992 *num_bytes_written += num_bytes_read;
999 oal_check_for_errors("AudioStream::WriteWaveData() end");
1002 SDL_UnlockMutex(Global_service_lock);
1010 // Helper function to calculate max size of sound buffer write operation, i.e. how much
1011 // free space there is in buffer.
1012 uint AudioStream::GetMaxWriteSize()
1014 uint dwMaxSize = m_cbBufSize;
1017 oal_check_for_errors("AudioStream::GetMaxWriteSize() begin");
1019 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &n);
1021 alGetSourcei(m_source_id, AL_BUFFERS_QUEUED, &q);
1023 if ( !n && (q >= MAX_STREAM_BUFFERS) ) {
1024 //all buffers queued
1028 oal_check_for_errors("AudioStream::GetMaxWriteSize() end");
1030 // nprintf(("Alan","Max write size: %d\n", dwMaxSize));
1034 #define VOLUME_ATTENUATION_BEFORE_CUTOFF 0.03f // 12db
1035 #define VOLUME_ATTENUATION 0.65f
1037 bool AudioStream::ServiceBuffer()
1042 if (type == ASF_FREE) {
1047 if (m_lCutoffVolume == 0.0f) {
1049 // nprintf(("Alan","Volume is: %d\n",vol));
1050 m_lCutoffVolume = vol * VOLUME_ATTENUATION_BEFORE_CUTOFF;
1053 vol = Get_Volume() * VOLUME_ATTENUATION;
1054 // nprintf(("Alan","Volume is now: %d\n",vol));
1057 // nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
1058 // nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
1059 if (vol < m_lCutoffVolume) {
1061 m_lCutoffVolume = 0.0f;
1063 if (m_bDestroy_when_faded) {
1076 // All of sound not played yet, send more data to buffer
1077 uint dwFreeSpace = GetMaxWriteSize();
1079 // Determine free space in sound buffer
1081 // Some wave data remains, but not enough to fill free space
1082 // Send wave data to buffer, fill remainder of free space with silence
1083 uint num_bytes_written;
1085 if ( WriteWaveData(dwFreeSpace, &num_bytes_written) ) {
1086 // nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));
1088 if (m_pwavefile->m_total_uncompressed_bytes_read >= m_pwavefile->m_max_uncompressed_bytes_to_read) {
1089 m_fade_timer_id = timer_get_milliseconds() + 1700; // start fading 1.7 seconds from now
1090 m_finished_id = timer_get_milliseconds() + 2000; // 2 seconds left to play out buffer
1091 m_pwavefile->m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1094 if ( (m_fade_timer_id > 0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
1095 m_fade_timer_id = 0;
1099 if ( (m_finished_id > 0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
1101 m_bPastLimit = true;
1104 // see if we're done
1107 alGetSourcei(m_source_id, AL_SOURCE_STATE, &state);
1109 if ( m_bReadingDone && (state != AL_PLAYING) ) {
1110 if ( m_bDestroy_when_faded == true ) {
1112 // Reset reentrancy semaphore
1117 // All of sound has played, stop playback or loop again
1118 if ( m_bLooping && !m_bFade) {
1119 Play(m_lVolume, m_bLooping);
1125 // Error writing wave data
1135 void AudioStream::Cue()
1137 uint num_bytes_written;
1141 m_fade_timer_id = 0;
1143 m_bPastLimit = false;
1145 m_lCutoffVolume = 0.0f;
1147 m_bDestroy_when_faded = false;
1152 // Reset file ptr, etc
1155 // Unqueue all buffers
1156 ALint buffers_processed = 0;
1157 ALuint buffer_id = 0;
1159 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed);
1161 while (buffers_processed) {
1162 alSourceUnqueueBuffers(m_source_id, 1, &buffer_id);
1164 buffers_processed--;
1167 // Fill buffer with wave data
1168 WriteWaveData(m_cbBufSize, &num_bytes_written, 0);
1175 void AudioStream::Play(float volume, int looping)
1177 if ( m_buffer_ids[0] ) {
1178 oal_check_for_errors("AudioStream::Play() begin");
1182 if ( m_bIsPaused == false)
1186 // get source id if we don't have one
1187 if ( !m_source_id ) {
1188 sound_channel *chan = oal_get_free_channel(1.0f, -1, SND_PRIORITY_MUST_PLAY);
1191 m_source_id = chan->source_id;
1203 // Cue for playback if necessary
1208 m_nTimeStarted = timer_get_milliseconds();
1211 // Kick off timer to service buffer
1212 m_timer.constructor();
1214 m_timer.Create(m_nBufService, (ptr_u)this, TimerCallback);
1216 alSourcef(m_source_id, AL_GAIN, m_lVolume);
1217 alSource3f(m_source_id, AL_POSITION, 0.0f, 0.0f, 0.0f);
1218 alSource3f(m_source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1219 alSource3f(m_source_id, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1220 alSourcef(m_source_id, AL_ROLLOFF_FACTOR, 0.0f);
1221 alSourcei(m_source_id, AL_SOURCE_RELATIVE, AL_TRUE);
1222 alSourcei(m_source_id, AL_LOOPING, AL_FALSE);
1224 alSourcePlay(m_source_id);
1226 // Playback begun, no longer cued
1228 m_bIsPaused = false;
1230 oal_check_for_errors("AudioStream::Play() end");
1234 // Timer callback for Timer object created by ::Play method.
1235 bool AudioStream::TimerCallback(ptr_u dwUser)
1237 // dwUser contains ptr to AudioStream object
1238 AudioStream * pas = (AudioStream *) dwUser;
1240 return (pas->ServiceBuffer ());
1243 void AudioStream::Set_Byte_Cutoff(unsigned int byte_cutoff)
1245 if ( m_pwavefile == NULL )
1248 m_pwavefile->m_max_uncompressed_bytes_to_read = byte_cutoff;
1251 uint AudioStream::Get_Bytes_Committed(void)
1253 if (m_pwavefile == NULL) {
1257 return m_pwavefile->m_total_uncompressed_bytes_read;
1261 void AudioStream::Fade_and_Destroy()
1264 m_bDestroy_when_faded = true;
1268 void AudioStream::Fade_and_Stop()
1271 m_bDestroy_when_faded = false;
1275 void AudioStream::Stop(bool paused)
1279 alSourcePause(m_source_id);
1281 alSourceStop(m_source_id);
1282 alSourcei(m_source_id, AL_BUFFER, 0);
1287 m_bIsPaused = paused;
1289 // Delete Timer object
1290 m_timer.destructor();
1295 void AudioStream::Stop_and_Rewind()
1299 alSourceStop(m_source_id);
1300 alSourcei(m_source_id, AL_BUFFER, 0);
1303 // Delete Timer object
1304 m_timer.destructor();
1309 m_fCued = false; // this will cause wave file to start from beginning
1310 m_bReadingDone = false;
1314 void AudioStream::Set_Volume(float vol)
1317 alSourcef(m_source_id, AL_GAIN, vol);
1325 float AudioStream::Get_Volume()
1331 #define MAX_AUDIO_STREAMS 30
1332 static AudioStream *Audio_streams = NULL;
1335 void audiostream_init()
1337 if (Audiostream_inited) {
1341 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1342 // disk during a load/cue
1343 if (Wavedata_load_buffer == NULL) {
1344 Wavedata_load_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1346 if (Wavedata_load_buffer == NULL) {
1351 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1352 // disk during a service interval
1353 if (Wavedata_service_buffer == NULL) {
1354 Wavedata_service_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1356 if (Wavedata_service_buffer == NULL) {
1361 // Allocate memory for the buffer which holds the compressed wave data that is read from the hard disk
1362 if (Compressed_buffer == NULL) {
1363 Compressed_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1365 if (Compressed_buffer == NULL) {
1370 if (Compressed_service_buffer == NULL) {
1371 Compressed_service_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1373 if (Compressed_service_buffer == NULL) {
1378 if (Audio_streams == NULL) {
1379 Audio_streams = (AudioStream*)malloc(sizeof(AudioStream) * MAX_AUDIO_STREAMS);
1381 if (Audio_streams == NULL) {
1386 for (int i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1387 Audio_streams[i].Init_Data();
1388 Audio_streams[i].status = ASF_FREE;
1389 Audio_streams[i].type = ASF_NONE;
1392 Global_service_lock = SDL_CreateMutex();
1394 Audiostream_inited = 1;
1399 if (Wavedata_service_buffer) {
1400 free(Wavedata_service_buffer);
1401 Wavedata_service_buffer = NULL;
1404 if (Compressed_buffer) {
1405 free(Compressed_buffer);
1406 Compressed_buffer = NULL;
1409 if (Compressed_service_buffer) {
1410 free(Compressed_service_buffer);
1411 Compressed_service_buffer = NULL;
1414 if (Audio_streams) {
1415 free(Audio_streams);
1416 Audio_streams = NULL;
1419 Audiostream_inited = 0;
1422 // Close down the audiostream system. Must call audiostream_init() before any audiostream functions can
1424 void audiostream_close()
1426 if ( !Audiostream_inited ) {
1430 SDL_assert( Audio_streams != NULL );
1432 for (int i = 0; i < MAX_AUDIO_STREAMS; i++) {
1433 if ( Audio_streams[i].status == ASF_USED ) {
1434 Audio_streams[i].status = ASF_FREE;
1435 Audio_streams[i].Destroy();
1439 free(Audio_streams);
1440 Audio_streams = NULL;
1442 // free global buffers
1443 if (Wavedata_load_buffer) {
1444 free(Wavedata_load_buffer);
1445 Wavedata_load_buffer = NULL;
1448 if (Wavedata_service_buffer) {
1449 free(Wavedata_service_buffer);
1450 Wavedata_service_buffer = NULL;
1453 if (Compressed_buffer) {
1454 free(Compressed_buffer);
1455 Compressed_buffer = NULL;
1458 if (Compressed_service_buffer) {
1459 free(Compressed_service_buffer);
1460 Compressed_service_buffer = NULL;
1463 SDL_DestroyMutex( Global_service_lock );
1465 Audiostream_inited = 0;
1469 // Open a digital sound file for streaming
1471 // input: filename => disk filename of sound file
1472 // type => what type of audio stream do we want to open:
1477 // returns: success => handle to identify streaming sound
1479 int audiostream_open( const char *filename, int type )
1483 if ( !Audiostream_inited ) {
1487 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1488 if (Audio_streams[i].status == ASF_FREE) {
1489 Audio_streams[i].status = ASF_USED;
1490 Audio_streams[i].type = type;
1495 if (i == MAX_AUDIO_STREAMS) {
1496 nprintf(("Sound", "SOUND => No more audio streams available!\n"));
1503 Audio_streams[i].m_bits_per_sample_uncompressed = 8;
1506 case ASF_EVENTMUSIC:
1507 Audio_streams[i].m_bits_per_sample_uncompressed = 16;
1515 if ( !Audio_streams[i].Create(filename) ) {
1516 Audio_streams[i].status = ASF_FREE;
1523 void audiostream_close_file(int i, int fade)
1525 if ( !Audiostream_inited ) {
1533 SDL_assert( i < MAX_AUDIO_STREAMS );
1535 if (Audio_streams[i].status == ASF_FREE) {
1540 Audio_streams[i].Fade_and_Destroy();
1542 Audio_streams[i].Destroy();
1546 void audiostream_close_all(int fade)
1550 if ( !Audiostream_inited ) {
1554 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1555 if (Audio_streams[i].status == ASF_FREE) {
1559 audiostream_close_file(i, fade);
1563 void audiostream_play(int i, float volume, int looping)
1565 if ( !Audiostream_inited ) {
1573 SDL_assert( i < MAX_AUDIO_STREAMS );
1575 if (Audio_streams[i].status == ASF_FREE) {
1579 if (volume < 0.0f) {
1580 volume = Audio_streams[i].Get_Default_Volume();
1583 Audio_streams[i].Set_Default_Volume(volume);
1584 Audio_streams[i].Play(volume, looping);
1587 // use as buffer service function
1588 bool audiostream_is_playing(int i)
1590 if ( !Audiostream_inited ) {
1598 SDL_assert( i < MAX_AUDIO_STREAMS );
1600 if (Audio_streams[i].status == ASF_FREE) {
1604 return Audio_streams[i].Is_Playing();
1607 void audiostream_stop(int i, int rewind, int paused)
1609 if ( !Audiostream_inited ) {
1617 SDL_assert( i < MAX_AUDIO_STREAMS );
1619 if (Audio_streams[i].status == ASF_FREE) {
1624 Audio_streams[i].Stop_and_Rewind();
1626 Audio_streams[i].Stop( (paused != 0) );
1630 void audiostream_set_volume_all(float volume, int type)
1634 if ( !Audiostream_inited ) {
1638 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1639 if (Audio_streams[i].status == ASF_FREE) {
1643 if (Audio_streams[i].type == type) {
1644 Audio_streams[i].Set_Volume(volume);
1649 void audiostream_set_volume(int i, float volume)
1651 if ( !Audiostream_inited ) {
1659 SDL_assert( i < MAX_AUDIO_STREAMS );
1661 if (Audio_streams[i].status == ASF_FREE) {
1665 Audio_streams[i].Set_Volume(volume);
1668 bool audiostream_is_paused(int i)
1670 if ( !Audiostream_inited ) {
1678 SDL_assert( i < MAX_AUDIO_STREAMS );
1680 if (Audio_streams[i].status == ASF_FREE) {
1684 return Audio_streams[i].Is_Paused();
1687 void audiostream_set_byte_cutoff(int i, uint cutoff)
1689 if ( !Audiostream_inited ) {
1697 SDL_assert( i < MAX_AUDIO_STREAMS );
1699 if (Audio_streams[i].status == ASF_FREE) {
1703 Audio_streams[i].Set_Byte_Cutoff(cutoff);
1706 uint audiostream_get_bytes_committed(int i)
1708 if ( !Audiostream_inited ) {
1716 SDL_assert( i < MAX_AUDIO_STREAMS );
1718 if (Audio_streams[i].status == ASF_FREE) {
1722 return Audio_streams[i].Get_Bytes_Committed();
1725 bool audiostream_done_reading(int i)
1727 if ( !Audiostream_inited ) {
1735 SDL_assert( i < MAX_AUDIO_STREAMS );
1737 if (Audio_streams[i].status == ASF_FREE) {
1741 return Audio_streams[i].Is_Past_Limit();
1744 int audiostream_is_inited()
1746 return Audiostream_inited;
1749 void audiostream_pause(int i)
1751 if ( !Audiostream_inited ) {
1759 SDL_assert( i < MAX_AUDIO_STREAMS );
1761 if (Audio_streams[i].status == ASF_FREE) {
1765 if ( audiostream_is_playing(i) ) {
1766 audiostream_stop(i, 0, 1);
1770 void audiostream_pause_all()
1774 if ( !Audiostream_inited ) {
1778 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1779 if (Audio_streams[i].status == ASF_FREE) {
1783 audiostream_pause(i);
1787 void audiostream_unpause(int i)
1791 if ( !Audiostream_inited ) {
1799 SDL_assert( i < MAX_AUDIO_STREAMS );
1801 if (Audio_streams[i].status == ASF_FREE) {
1805 if ( audiostream_is_paused(i) ) {
1806 is_looping = Audio_streams[i].Is_looping();
1807 audiostream_play(i, -1.0f, is_looping);
1811 void audiostream_unpause_all()
1815 if ( !Audiostream_inited ) {
1819 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1820 if (Audio_streams[i].status == ASF_FREE) {
1824 audiostream_unpause(i);