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 (num_bytes_read < 0) {
957 } else if (num_bytes_read > 0) {
958 alBufferData(m_buffer_ids[ib], m_pwavefile->GetOALFormat(), uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.sample_rate);
959 alSourceQueueBuffers(m_source_id, 1, &m_buffer_ids[ib]);
960 *num_bytes_written += num_bytes_read;
964 ALint buffers_processed = 0;
965 ALuint buffer_id = 0;
967 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed);
969 while (buffers_processed) {
970 alSourceUnqueueBuffers(m_source_id, 1, &buffer_id);
972 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
974 if (num_bytes_read < 0) {
976 } else if (num_bytes_read > 0) {
977 alBufferData(buffer_id, m_pwavefile->GetOALFormat(), uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.sample_rate);
978 alSourceQueueBuffers(m_source_id, 1, &buffer_id);
979 *num_bytes_written += num_bytes_read;
986 oal_check_for_errors("AudioStream::WriteWaveData() end");
989 SDL_UnlockMutex(Global_service_lock);
997 // Helper function to calculate max size of sound buffer write operation, i.e. how much
998 // free space there is in buffer.
999 uint AudioStream::GetMaxWriteSize()
1001 uint dwMaxSize = m_cbBufSize;
1004 oal_check_for_errors("AudioStream::GetMaxWriteSize() begin");
1006 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &n);
1008 alGetSourcei(m_source_id, AL_BUFFERS_QUEUED, &q);
1010 if ( !n && (q >= MAX_STREAM_BUFFERS) ) {
1011 //all buffers queued
1015 oal_check_for_errors("AudioStream::GetMaxWriteSize() end");
1017 // nprintf(("Alan","Max write size: %d\n", dwMaxSize));
1021 #define VOLUME_ATTENUATION_BEFORE_CUTOFF 0.03f // 12db
1022 #define VOLUME_ATTENUATION 0.65f
1024 bool AudioStream::ServiceBuffer()
1029 if (type == ASF_FREE) {
1034 if (m_lCutoffVolume == 0.0f) {
1036 // nprintf(("Alan","Volume is: %d\n",vol));
1037 m_lCutoffVolume = vol * VOLUME_ATTENUATION_BEFORE_CUTOFF;
1040 vol = Get_Volume() * VOLUME_ATTENUATION;
1041 // nprintf(("Alan","Volume is now: %d\n",vol));
1044 // nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
1045 // nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
1046 if (vol < m_lCutoffVolume) {
1048 m_lCutoffVolume = 0.0f;
1050 if (m_bDestroy_when_faded) {
1063 // All of sound not played yet, send more data to buffer
1064 uint dwFreeSpace = GetMaxWriteSize();
1066 // Determine free space in sound buffer
1068 // Some wave data remains, but not enough to fill free space
1069 // Send wave data to buffer, fill remainder of free space with silence
1070 uint num_bytes_written;
1072 if ( WriteWaveData(dwFreeSpace, &num_bytes_written) ) {
1073 // nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));
1075 if (m_pwavefile->m_total_uncompressed_bytes_read >= m_pwavefile->m_max_uncompressed_bytes_to_read) {
1076 m_fade_timer_id = timer_get_milliseconds() + 1700; // start fading 1.7 seconds from now
1077 m_finished_id = timer_get_milliseconds() + 2000; // 2 seconds left to play out buffer
1078 m_pwavefile->m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1081 if ( (m_fade_timer_id > 0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
1082 m_fade_timer_id = 0;
1086 if ( (m_finished_id > 0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
1088 m_bPastLimit = true;
1091 // see if we're done
1094 alGetSourcei(m_source_id, AL_SOURCE_STATE, &state);
1096 if ( m_bReadingDone && (state != AL_PLAYING) ) {
1097 if ( m_bDestroy_when_faded == true ) {
1099 // Reset reentrancy semaphore
1104 // All of sound has played, stop playback or loop again
1105 if ( m_bLooping && !m_bFade) {
1106 Play(m_lVolume, m_bLooping);
1112 // Error writing wave data
1122 void AudioStream::Cue()
1124 uint num_bytes_written;
1128 m_fade_timer_id = 0;
1130 m_bPastLimit = false;
1132 m_lCutoffVolume = 0.0f;
1134 m_bDestroy_when_faded = false;
1139 // Reset file ptr, etc
1142 // Unqueue all buffers
1143 ALint buffers_processed = 0;
1144 ALuint buffer_id = 0;
1146 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed);
1148 while (buffers_processed) {
1149 alSourceUnqueueBuffers(m_source_id, 1, &buffer_id);
1151 buffers_processed--;
1154 // Fill buffer with wave data
1155 WriteWaveData(m_cbBufSize, &num_bytes_written, 0);
1162 void AudioStream::Play(float volume, int looping)
1164 if ( m_buffer_ids[0] ) {
1165 oal_check_for_errors("AudioStream::Play() begin");
1169 if ( m_bIsPaused == false)
1173 // get source id if we don't have one
1174 if ( !m_source_id ) {
1175 sound_channel *chan = oal_get_free_channel(1.0f, -1, SND_PRIORITY_MUST_PLAY);
1178 m_source_id = chan->source_id;
1184 // Cue for playback if necessary
1195 m_nTimeStarted = timer_get_milliseconds();
1198 // Kick off timer to service buffer
1199 m_timer.constructor();
1201 m_timer.Create(m_nBufService, (ptr_u)this, TimerCallback);
1203 alSourcef(m_source_id, AL_GAIN, m_lVolume);
1204 alSource3f(m_source_id, AL_POSITION, 0.0f, 0.0f, 0.0f);
1205 alSource3f(m_source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1206 alSource3f(m_source_id, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1207 alSourcef(m_source_id, AL_ROLLOFF_FACTOR, 0.0f);
1208 alSourcei(m_source_id, AL_SOURCE_RELATIVE, AL_TRUE);
1209 alSourcei(m_source_id, AL_LOOPING, AL_FALSE);
1211 alSourcePlay(m_source_id);
1213 // Playback begun, no longer cued
1215 m_bIsPaused = false;
1217 oal_check_for_errors("AudioStream::Play() end");
1221 // Timer callback for Timer object created by ::Play method.
1222 bool AudioStream::TimerCallback(ptr_u dwUser)
1224 // dwUser contains ptr to AudioStream object
1225 AudioStream * pas = (AudioStream *) dwUser;
1227 return (pas->ServiceBuffer ());
1230 void AudioStream::Set_Byte_Cutoff(unsigned int byte_cutoff)
1232 if ( m_pwavefile == NULL )
1235 m_pwavefile->m_max_uncompressed_bytes_to_read = byte_cutoff;
1238 uint AudioStream::Get_Bytes_Committed(void)
1240 if (m_pwavefile == NULL) {
1244 return m_pwavefile->m_total_uncompressed_bytes_read;
1248 void AudioStream::Fade_and_Destroy()
1251 m_bDestroy_when_faded = true;
1255 void AudioStream::Fade_and_Stop()
1258 m_bDestroy_when_faded = false;
1262 void AudioStream::Stop(bool paused)
1266 alSourcePause(m_source_id);
1268 alSourceStop(m_source_id);
1269 alSourcei(m_source_id, AL_BUFFER, 0);
1274 m_bIsPaused = paused;
1276 // Delete Timer object
1277 m_timer.destructor();
1282 void AudioStream::Stop_and_Rewind()
1286 alSourceStop(m_source_id);
1287 alSourcei(m_source_id, AL_BUFFER, 0);
1290 // Delete Timer object
1291 m_timer.destructor();
1296 m_fCued = false; // this will cause wave file to start from beginning
1297 m_bReadingDone = false;
1301 void AudioStream::Set_Volume(float vol)
1304 alSourcef(m_source_id, AL_GAIN, vol);
1312 float AudioStream::Get_Volume()
1318 #define MAX_AUDIO_STREAMS 30
1319 static AudioStream *Audio_streams = NULL;
1322 void audiostream_init()
1324 if (Audiostream_inited) {
1328 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1329 // disk during a load/cue
1330 if (Wavedata_load_buffer == NULL) {
1331 Wavedata_load_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1333 if (Wavedata_load_buffer == NULL) {
1338 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1339 // disk during a service interval
1340 if (Wavedata_service_buffer == NULL) {
1341 Wavedata_service_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1343 if (Wavedata_service_buffer == NULL) {
1348 // Allocate memory for the buffer which holds the compressed wave data that is read from the hard disk
1349 if (Compressed_buffer == NULL) {
1350 Compressed_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1352 if (Compressed_buffer == NULL) {
1357 if (Compressed_service_buffer == NULL) {
1358 Compressed_service_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1360 if (Compressed_service_buffer == NULL) {
1365 if (Audio_streams == NULL) {
1366 Audio_streams = (AudioStream*)malloc(sizeof(AudioStream) * MAX_AUDIO_STREAMS);
1368 if (Audio_streams == NULL) {
1373 for (int i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1374 Audio_streams[i].Init_Data();
1375 Audio_streams[i].status = ASF_FREE;
1376 Audio_streams[i].type = ASF_NONE;
1379 Global_service_lock = SDL_CreateMutex();
1381 Audiostream_inited = 1;
1386 if (Wavedata_service_buffer) {
1387 free(Wavedata_service_buffer);
1388 Wavedata_service_buffer = NULL;
1391 if (Compressed_buffer) {
1392 free(Compressed_buffer);
1393 Compressed_buffer = NULL;
1396 if (Compressed_service_buffer) {
1397 free(Compressed_service_buffer);
1398 Compressed_service_buffer = NULL;
1401 if (Audio_streams) {
1402 free(Audio_streams);
1403 Audio_streams = NULL;
1406 Audiostream_inited = 0;
1409 // Close down the audiostream system. Must call audiostream_init() before any audiostream functions can
1411 void audiostream_close()
1413 if ( !Audiostream_inited ) {
1417 SDL_assert( Audio_streams != NULL );
1419 for (int i = 0; i < MAX_AUDIO_STREAMS; i++) {
1420 if ( Audio_streams[i].status == ASF_USED ) {
1421 Audio_streams[i].status = ASF_FREE;
1422 Audio_streams[i].Destroy();
1426 free(Audio_streams);
1427 Audio_streams = NULL;
1429 // free global buffers
1430 if (Wavedata_load_buffer) {
1431 free(Wavedata_load_buffer);
1432 Wavedata_load_buffer = NULL;
1435 if (Wavedata_service_buffer) {
1436 free(Wavedata_service_buffer);
1437 Wavedata_service_buffer = NULL;
1440 if (Compressed_buffer) {
1441 free(Compressed_buffer);
1442 Compressed_buffer = NULL;
1445 if (Compressed_service_buffer) {
1446 free(Compressed_service_buffer);
1447 Compressed_service_buffer = NULL;
1450 SDL_DestroyMutex( Global_service_lock );
1452 Audiostream_inited = 0;
1456 // Open a digital sound file for streaming
1458 // input: filename => disk filename of sound file
1459 // type => what type of audio stream do we want to open:
1464 // returns: success => handle to identify streaming sound
1466 int audiostream_open( const char *filename, int type )
1470 if ( !Audiostream_inited ) {
1474 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1475 if (Audio_streams[i].status == ASF_FREE) {
1476 Audio_streams[i].status = ASF_USED;
1477 Audio_streams[i].type = type;
1482 if (i == MAX_AUDIO_STREAMS) {
1483 nprintf(("Sound", "SOUND => No more audio streams available!\n"));
1490 Audio_streams[i].m_bits_per_sample_uncompressed = 8;
1493 case ASF_EVENTMUSIC:
1494 Audio_streams[i].m_bits_per_sample_uncompressed = 16;
1502 if ( !Audio_streams[i].Create(filename) ) {
1503 Audio_streams[i].status = ASF_FREE;
1510 void audiostream_close_file(int i, int fade)
1512 if ( !Audiostream_inited ) {
1520 SDL_assert( i < MAX_AUDIO_STREAMS );
1522 if (Audio_streams[i].status == ASF_FREE) {
1527 Audio_streams[i].Fade_and_Destroy();
1529 Audio_streams[i].Destroy();
1533 void audiostream_close_all(int fade)
1537 if ( !Audiostream_inited ) {
1541 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1542 if (Audio_streams[i].status == ASF_FREE) {
1546 audiostream_close_file(i, fade);
1550 void audiostream_play(int i, float volume, int looping)
1552 if ( !Audiostream_inited ) {
1560 SDL_assert( i < MAX_AUDIO_STREAMS );
1562 if (Audio_streams[i].status == ASF_FREE) {
1566 if (volume < 0.0f) {
1567 volume = Audio_streams[i].Get_Default_Volume();
1570 Audio_streams[i].Set_Default_Volume(volume);
1571 Audio_streams[i].Play(volume, looping);
1574 // use as buffer service function
1575 bool audiostream_is_playing(int i)
1577 if ( !Audiostream_inited ) {
1585 SDL_assert( i < MAX_AUDIO_STREAMS );
1587 if (Audio_streams[i].status == ASF_FREE) {
1591 return Audio_streams[i].Is_Playing();
1594 void audiostream_stop(int i, int rewind, int paused)
1596 if ( !Audiostream_inited ) {
1604 SDL_assert( i < MAX_AUDIO_STREAMS );
1606 if (Audio_streams[i].status == ASF_FREE) {
1611 Audio_streams[i].Stop_and_Rewind();
1613 Audio_streams[i].Stop( (paused != 0) );
1617 void audiostream_set_volume_all(float volume, int type)
1621 if ( !Audiostream_inited ) {
1625 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1626 if (Audio_streams[i].status == ASF_FREE) {
1630 if (Audio_streams[i].type == type) {
1631 Audio_streams[i].Set_Volume(volume);
1636 void audiostream_set_volume(int i, float volume)
1638 if ( !Audiostream_inited ) {
1646 SDL_assert( i < MAX_AUDIO_STREAMS );
1648 if (Audio_streams[i].status == ASF_FREE) {
1652 Audio_streams[i].Set_Volume(volume);
1655 bool audiostream_is_paused(int i)
1657 if ( !Audiostream_inited ) {
1665 SDL_assert( i < MAX_AUDIO_STREAMS );
1667 if (Audio_streams[i].status == ASF_FREE) {
1671 return Audio_streams[i].Is_Paused();
1674 void audiostream_set_byte_cutoff(int i, uint cutoff)
1676 if ( !Audiostream_inited ) {
1684 SDL_assert( i < MAX_AUDIO_STREAMS );
1686 if (Audio_streams[i].status == ASF_FREE) {
1690 Audio_streams[i].Set_Byte_Cutoff(cutoff);
1693 uint audiostream_get_bytes_committed(int i)
1695 if ( !Audiostream_inited ) {
1703 SDL_assert( i < MAX_AUDIO_STREAMS );
1705 if (Audio_streams[i].status == ASF_FREE) {
1709 return Audio_streams[i].Get_Bytes_Committed();
1712 bool audiostream_done_reading(int i)
1714 if ( !Audiostream_inited ) {
1722 SDL_assert( i < MAX_AUDIO_STREAMS );
1724 if (Audio_streams[i].status == ASF_FREE) {
1728 return Audio_streams[i].Is_Past_Limit();
1731 int audiostream_is_inited()
1733 return Audiostream_inited;
1736 void audiostream_pause(int i)
1738 if ( !Audiostream_inited ) {
1746 SDL_assert( i < MAX_AUDIO_STREAMS );
1748 if (Audio_streams[i].status == ASF_FREE) {
1752 if ( audiostream_is_playing(i) ) {
1753 audiostream_stop(i, 0, 1);
1757 void audiostream_pause_all()
1761 if ( !Audiostream_inited ) {
1765 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1766 if (Audio_streams[i].status == ASF_FREE) {
1770 audiostream_pause(i);
1774 void audiostream_unpause(int i)
1778 if ( !Audiostream_inited ) {
1786 SDL_assert( i < MAX_AUDIO_STREAMS );
1788 if (Audio_streams[i].status == ASF_FREE) {
1792 if ( audiostream_is_paused(i) ) {
1793 is_looping = Audio_streams[i].Is_looping();
1794 audiostream_play(i, -1.0f, is_looping);
1798 void audiostream_unpause_all()
1802 if ( !Audiostream_inited ) {
1806 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1807 if (Audio_streams[i].status == ASF_FREE) {
1811 audiostream_unpause(i);