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;
359 m_abort_next_read = false;
362 void WaveFile::Close()
365 if (m_pwfmt_original) {
366 free(m_pwfmt_original);
367 m_pwfmt_original = NULL;
370 if (m_hStream_open) {
371 ACM_stream_close((void*)m_hStream);
382 bool WaveFile::Open(const char *pszFilename)
385 bool fRtn = true; // assume success
387 uint tag = 0, size = 0, next_chunk;
389 m_total_uncompressed_bytes_read = 0;
390 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
392 m_pwfmt_original = (WAVE_chunk*) malloc (sizeof(WAVE_chunk));
394 if (m_pwfmt_original == NULL) {
398 cfp = cfopen(pszFilename, "rb");
404 // check for valid file type
405 id = cfread_int(cfp);
408 if (id != 0x46464952) {
409 nprintf(("Error", "Not a WAVE file '%s'\n", pszFilename));
416 // check for valid RIFF type
417 id = cfread_int(cfp);
420 if (id != 0x45564157) {
421 nprintf(("Error", "Not a WAVE file '%s'\n", pszFilename));
426 tag = cfread_uint(cfp);
427 size = cfread_uint(cfp);
429 next_chunk = cftell(cfp) + size;
434 m_pwfmt_original->code = cfread_short(cfp);
435 m_pwfmt_original->num_channels = cfread_ushort(cfp);
436 m_pwfmt_original->sample_rate = cfread_uint(cfp);
437 m_pwfmt_original->bytes_per_second = cfread_uint(cfp);
438 m_pwfmt_original->block_align = cfread_ushort(cfp);
439 m_pwfmt_original->bits_per_sample = cfread_ushort(cfp);
441 if (m_pwfmt_original->code != 1) {
442 m_pwfmt_original->extra_size = cfread_ushort(cfp);
445 if (m_pwfmt_original->extra_size) {
446 m_pwfmt_original->extra_data = (ubyte*) malloc (m_pwfmt_original->extra_size);
447 SDL_assert( m_pwfmt_original->extra_data != NULL );
449 if (m_pwfmt_original->extra_data == NULL) {
453 cfread(m_pwfmt_original->extra_data, m_pwfmt_original->extra_size, 1, cfp);
461 m_nDataSize = size; // size of data, compressed size if ADPCM
462 m_data_bytes_left = size;
463 m_data_offset = cftell(cfp);
470 // drop everything else
475 cfseek(cfp, next_chunk, CF_SEEK_SET);
478 // we force PCM format, so keep track of original format for later
479 switch (m_pwfmt_original->code) {
480 case WAVE_FORMAT_PCM:
481 m_wave_format = WAVE_FORMAT_PCM;
482 m_wfmt.bits_per_sample = m_pwfmt_original->bits_per_sample;
485 case WAVE_FORMAT_ADPCM:
486 m_wave_format = WAVE_FORMAT_ADPCM;
487 m_wfmt.bits_per_sample = 16;
488 m_bits_per_sample_uncompressed = 16;
492 nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n", m_pwfmt_original->code));
499 m_wfmt.code = WAVE_FORMAT_PCM;
500 m_wfmt.num_channels = m_pwfmt_original->num_channels;
501 m_wfmt.sample_rate = m_pwfmt_original->sample_rate;
502 m_wfmt.extra_size = 0;
503 m_wfmt.block_align = (ushort)(( m_wfmt.num_channels * m_wfmt.bits_per_sample ) / 8);
504 m_wfmt.bytes_per_second = m_wfmt.block_align * m_wfmt.sample_rate;
507 m_oal_format = AL_FORMAT_MONO8;
509 if (m_wfmt.num_channels == 1) {
510 if (m_wfmt.bits_per_sample == 8) {
511 m_oal_format = AL_FORMAT_MONO8;
512 } else if (m_wfmt.bits_per_sample == 16) {
513 m_oal_format = AL_FORMAT_MONO16;
515 } else if (m_wfmt.num_channels == 2) {
516 if (m_wfmt.bits_per_sample == 8) {
517 m_oal_format = AL_FORMAT_STEREO8;
518 } else if (m_wfmt.bits_per_sample == 16) {
519 m_oal_format = AL_FORMAT_STEREO16;
523 // Init some member data from format chunk
524 m_nBlockAlign = m_pwfmt_original->block_align;
525 m_nUncompressedAvgDataRate = m_wfmt.bytes_per_second;
531 // Handle all errors here
532 nprintf(("SOUND","SOUND ==> Could not open wave file %s for streaming\n", pszFilename));
536 if (m_pwfmt_original) {
537 free(m_pwfmt_original);
538 m_pwfmt_original = NULL;
552 // Set the file pointer to the start of wave data
556 bool fRtn = true; // assume success
559 m_total_uncompressed_bytes_read = 0;
560 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
562 rval = cfseek(cfp, m_data_offset, CF_SEEK_SET);
568 m_data_bytes_left = m_nDataSize;
569 m_abort_next_read = false;
576 // Returns number of bytes actually read.
578 // Returns -1 if there is nothing more to be read. This function can return 0, since
579 // sometimes the amount of bytes requested is too small for the ACM decompression to
580 // locate a suitable block
581 int WaveFile::Read(ubyte *pbDest, uint cbSize, int service)
583 void *dest_buf = NULL, *uncompressed_wave_data;
584 int rc, uncompressed_bytes_written;
585 uint src_bytes_used, convert_len, num_bytes_desired=0, num_bytes_read;
587 // nprintf(("Alan","Reqeusted: %d\n", cbSize));
590 uncompressed_wave_data = Wavedata_service_buffer;
592 uncompressed_wave_data = Wavedata_load_buffer;
595 switch (m_wave_format) {
596 case WAVE_FORMAT_PCM: {
597 num_bytes_desired = cbSize;
603 case WAVE_FORMAT_ADPCM: {
604 if ( !m_hStream_open ) {
605 if ( !ACM_stream_open(m_pwfmt_original, &m_wfxDest, (void**)&m_hStream, m_bits_per_sample_uncompressed) ) {
612 num_bytes_desired = cbSize;
615 dest_buf = Compressed_service_buffer;
617 dest_buf = Compressed_buffer;
620 if (num_bytes_desired <= 0) {
621 num_bytes_desired = 0;
622 // nprintf(("Alan","No bytes required for ADPCM time interval\n"));
624 num_bytes_desired = ACM_query_source_size((void*)m_hStream, cbSize);
625 // nprintf(("Alan","Num bytes desired: %d\n", num_bytes_desired));
632 nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n"));
642 // read data from disk
643 if (m_data_bytes_left <= 0) {
647 if ( (m_data_bytes_left > 0) && (num_bytes_desired > 0) ) {
650 if (num_bytes_desired <= (uint)m_data_bytes_left) {
651 num_bytes_read = num_bytes_desired;
653 num_bytes_read = m_data_bytes_left;
656 actual_read = cfread(dest_buf, 1, num_bytes_read, cfp);
658 if ( (actual_read <= 0) || (m_abort_next_read) ) {
662 if (num_bytes_desired >= (uint)m_data_bytes_left) {
663 m_abort_next_read = 1;
666 num_bytes_read = actual_read;
669 // convert data if necessary, to PCM
670 if (m_wave_format == WAVE_FORMAT_ADPCM) {
671 if ( num_bytes_read > 0 ) {
672 rc = ACM_convert((void*)m_hStream, (ubyte*)dest_buf, num_bytes_read, (ubyte*)uncompressed_wave_data, BIGBUF_SIZE, &convert_len, &src_bytes_used);
678 if (convert_len == 0) {
683 SDL_assert( src_bytes_used <= num_bytes_read );
685 if (src_bytes_used < num_bytes_read) {
686 // seek back file pointer to reposition before unused source data
687 cfseek(cfp, src_bytes_used - num_bytes_read, CF_SEEK_CUR);
690 // Adjust number of bytes left
691 m_data_bytes_left -= src_bytes_used;
692 m_nBytesPlayed += src_bytes_used;
693 uncompressed_bytes_written = convert_len;
695 // Successful read, keep running total of number of data bytes read
698 // Successful read, keep running total of number of data bytes read
699 // Adjust number of bytes left
700 m_data_bytes_left -= num_bytes_read;
701 m_nBytesPlayed += num_bytes_read;
702 uncompressed_bytes_written = num_bytes_read;
704 #if BYTE_ORDER == BIG_ENDIAN
705 if (m_wave_format == WAVE_FORMAT_PCM) {
706 // swap 16-bit sound data
707 if (m_wfmt.bits_per_sample == 16) {
710 for (int i = 0; i < uncompressed_bytes_written; i = (i+2)) {
711 swap_tmp = (ushort*)((ubyte*)dest_buf + i);
712 *swap_tmp = INTEL_SHORT(*swap_tmp);
722 uncompressed_bytes_written = 0;
725 m_total_uncompressed_bytes_read += uncompressed_bytes_written;
726 // nprintf(("Alan","Read: %d\n", uncompressed_bytes_written));
728 return uncompressed_bytes_written;
733 // Returns 8 bits of data representing silence for the Wave file format.
735 // Since we are dealing only with PCM format, we can fudge a bit and take
736 // advantage of the fact that for all PCM formats, silence can be represented
737 // by a single byte, repeated to make up the proper word size. The actual size
738 // of a word of wave data depends on the format:
740 // PCM Format Word Size Silence Data
741 // 8-bit mono 1 byte 0x80
742 // 8-bit stereo 2 bytes 0x8080
743 // 16-bit mono 2 bytes 0x0000
744 // 16-bit stereo 4 bytes 0x00000000
746 ubyte WaveFile::GetSilenceData()
748 ubyte bSilenceData = 0;
750 // Silence data depends on format of Wave file
751 if (m_pwfmt_original) {
752 if (m_wfmt.bits_per_sample == 8) {
753 // For 8-bit formats (unsigned, 0 to 255)
754 // Packed DWORD = 0x80808080;
756 } else if (m_wfmt.bits_per_sample == 16) {
757 // For 16-bit formats (signed, -32768 to 32767)
758 // Packed DWORD = 0x00000000;
771 // AudioStream class implementation
773 ////////////////////////////////////////////////////////////
775 // The following constants are the defaults for our streaming buffer operation.
776 static const ushort DefBufferLength = 2000; // default buffer length in msec
777 static const ushort DefBufferServiceInterval = 250; // default buffer service interval in msec
780 AudioStream::AudioStream()
785 AudioStream::~AudioStream()
789 void AudioStream::Init_Data()
795 m_bPastLimit = false;
797 m_bDestroy_when_faded = false;
798 m_lDefaultVolume = 1.0f;
800 m_lCutoffVolume = 0.0f;
802 m_silence_written = 0;
803 m_bReadingDone = false;
807 m_fPlaying = m_fCued = false;
808 m_lInService = false;
810 m_nBufLength = DefBufferLength;
812 m_nBufService = DefBufferServiceInterval;
815 memset(m_buffer_ids, 0, sizeof(m_buffer_ids));
817 m_play_buffer_id = 0;
821 bool AudioStream::Create(const char *pszFilename)
823 SDL_assert( pszFilename != NULL );
827 if (pszFilename == NULL) {
831 // make 100% sure we got a good filename
832 if ( !strlen(pszFilename) ) {
836 // Create a new WaveFile object
837 m_pwavefile = (WaveFile *)malloc(sizeof(WaveFile));
838 SDL_assert( m_pwavefile != NULL );
840 if (m_pwavefile == NULL) {
841 nprintf(("Sound", "SOUND => Failed to create WaveFile object %s\n\r", pszFilename));
848 m_pwavefile->m_bits_per_sample_uncompressed = m_bits_per_sample_uncompressed;
851 if ( m_pwavefile->Open(pszFilename) ) {
852 // Calculate sound buffer size in bytes
853 // Buffer size is average data rate times length of buffer
854 // No need for buffer to be larger than wave data though
855 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;
856 m_cbBufSize /= MAX_STREAM_BUFFERS;
857 // if the requested buffer size is too big then cap it
858 m_cbBufSize = (m_cbBufSize > BIGBUF_SIZE) ? BIGBUF_SIZE : m_cbBufSize;
860 // nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
862 // Create sound buffer
863 alGenBuffers(MAX_STREAM_BUFFERS, m_buffer_ids);
865 Snd_sram += m_cbBufSize * MAX_STREAM_BUFFERS;
867 // Error opening file
868 nprintf(("SOUND", "SOUND => Failed to open wave file: %s\n\r", pszFilename));
870 m_pwavefile->Close();
882 bool AudioStream::Destroy()
887 // Release sound buffer
888 alDeleteBuffers(MAX_STREAM_BUFFERS, m_buffer_ids);
890 Snd_sram -= m_cbBufSize;
892 // Delete WaveFile object
894 m_pwavefile->Close();
907 // Writes wave data to sound buffer. This is a helper method used by Create and
908 // ServiceBuffer; it's not exposed to users of the AudioStream class.
909 bool AudioStream::WriteWaveData(uint size, uint *num_bytes_written, int service)
911 ubyte *uncompressed_wave_data;
913 *num_bytes_written = 0;
915 if ( (size == 0) || m_bReadingDone ) {
919 if ( (m_buffer_ids[0] == 0) || !m_pwavefile ) {
924 SDL_LockMutex(Global_service_lock);
928 uncompressed_wave_data = Wavedata_service_buffer;
930 uncompressed_wave_data = Wavedata_load_buffer;
933 int num_bytes_read = 0;
935 oal_check_for_errors("AudioStream::WriteWaveData() begin");
938 for (int ib = 0; ib < MAX_STREAM_BUFFERS; ib++) {
939 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
941 if (num_bytes_read < 0) {
943 } else if (num_bytes_read > 0) {
944 alBufferData(m_buffer_ids[ib], m_pwavefile->GetOALFormat(), uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.sample_rate);
945 alSourceQueueBuffers(m_source_id, 1, &m_buffer_ids[ib]);
946 *num_bytes_written += num_bytes_read;
950 ALint buffers_processed = 0;
951 ALuint buffer_id = 0;
953 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed);
955 while (buffers_processed) {
956 alSourceUnqueueBuffers(m_source_id, 1, &buffer_id);
958 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
960 if (num_bytes_read < 0) {
962 } else if (num_bytes_read > 0) {
963 alBufferData(buffer_id, m_pwavefile->GetOALFormat(), uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.sample_rate);
964 alSourceQueueBuffers(m_source_id, 1, &buffer_id);
965 *num_bytes_written += num_bytes_read;
972 oal_check_for_errors("AudioStream::WriteWaveData() end");
975 SDL_UnlockMutex(Global_service_lock);
983 // Helper function to calculate max size of sound buffer write operation, i.e. how much
984 // free space there is in buffer.
985 uint AudioStream::GetMaxWriteSize()
987 uint dwMaxSize = m_cbBufSize;
990 oal_check_for_errors("AudioStream::GetMaxWriteSize() begin");
992 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &n);
994 alGetSourcei(m_source_id, AL_BUFFERS_QUEUED, &q);
996 if ( !n && (q >= MAX_STREAM_BUFFERS) ) {
1001 oal_check_for_errors("AudioStream::GetMaxWriteSize() end");
1003 // nprintf(("Alan","Max write size: %d\n", dwMaxSize));
1007 #define VOLUME_ATTENUATION_BEFORE_CUTOFF 0.03f // 12db
1008 #define VOLUME_ATTENUATION 0.65f
1010 bool AudioStream::ServiceBuffer()
1015 if (type == ASF_FREE) {
1020 if (m_lCutoffVolume == 0.0f) {
1022 // nprintf(("Alan","Volume is: %d\n",vol));
1023 m_lCutoffVolume = vol * VOLUME_ATTENUATION_BEFORE_CUTOFF;
1026 vol = Get_Volume() * VOLUME_ATTENUATION;
1027 // nprintf(("Alan","Volume is now: %d\n",vol));
1030 // nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
1031 // nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
1032 if (vol < m_lCutoffVolume) {
1034 m_lCutoffVolume = 0.0f;
1036 if (m_bDestroy_when_faded) {
1049 // All of sound not played yet, send more data to buffer
1050 uint dwFreeSpace = GetMaxWriteSize();
1052 // Determine free space in sound buffer
1054 // Some wave data remains, but not enough to fill free space
1055 // Send wave data to buffer, fill remainder of free space with silence
1056 uint num_bytes_written;
1058 if ( WriteWaveData(dwFreeSpace, &num_bytes_written) ) {
1059 // nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));
1061 if (m_pwavefile->m_total_uncompressed_bytes_read >= m_pwavefile->m_max_uncompressed_bytes_to_read) {
1062 m_fade_timer_id = timer_get_milliseconds() + 1700; // start fading 1.7 seconds from now
1063 m_finished_id = timer_get_milliseconds() + 2000; // 2 seconds left to play out buffer
1064 m_pwavefile->m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1067 if ( (m_fade_timer_id > 0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
1068 m_fade_timer_id = 0;
1072 if ( (m_finished_id > 0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
1074 m_bPastLimit = true;
1077 // see if we're done
1080 alGetSourcei(m_source_id, AL_SOURCE_STATE, &state);
1082 if ( m_bReadingDone && (state != AL_PLAYING) ) {
1083 if ( m_bDestroy_when_faded == true ) {
1085 // Reset reentrancy semaphore
1090 // All of sound has played, stop playback or loop again
1091 if ( m_bLooping && !m_bFade) {
1092 Play(m_lVolume, m_bLooping);
1098 // Error writing wave data
1108 void AudioStream::Cue()
1110 uint num_bytes_written;
1114 m_fade_timer_id = 0;
1116 m_bPastLimit = false;
1118 m_lCutoffVolume = 0.0f;
1120 m_bDestroy_when_faded = false;
1125 // Reset file ptr, etc
1128 // Unqueue all buffers
1129 ALint buffers_processed = 0;
1130 ALuint buffer_id = 0;
1132 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed);
1134 while (buffers_processed) {
1135 alSourceUnqueueBuffers(m_source_id, 1, &buffer_id);
1137 buffers_processed--;
1140 // Fill buffer with wave data
1141 WriteWaveData(m_cbBufSize, &num_bytes_written, 0);
1148 void AudioStream::Play(float volume, int looping)
1150 if ( m_buffer_ids[0] ) {
1151 oal_check_for_errors("AudioStream::Play() begin");
1155 if ( m_bIsPaused == false)
1159 // get source id if we don't have one
1160 if ( !m_source_id ) {
1161 sound_channel *chan = oal_get_free_channel(1.0f, -1, SND_PRIORITY_MUST_PLAY);
1162 m_source_id = chan->source_id;
1165 // Cue for playback if necessary
1176 m_nTimeStarted = timer_get_milliseconds();
1179 // Kick off timer to service buffer
1180 m_timer.constructor();
1182 m_timer.Create(m_nBufService, (ptr_u)this, TimerCallback);
1184 alSourcef(m_source_id, AL_GAIN, m_lVolume);
1185 alSource3f(m_source_id, AL_POSITION, 0.0f, 0.0f, 0.0f);
1186 alSource3f(m_source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1187 alSource3f(m_source_id, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1188 alSourcef(m_source_id, AL_ROLLOFF_FACTOR, 0.0f);
1189 alSourcei(m_source_id, AL_SOURCE_RELATIVE, AL_TRUE);
1190 alSourcei(m_source_id, AL_LOOPING, AL_FALSE);
1192 alSourcePlay(m_source_id);
1194 // Playback begun, no longer cued
1196 m_bIsPaused = false;
1198 oal_check_for_errors("AudioStream::Play() end");
1202 // Timer callback for Timer object created by ::Play method.
1203 bool AudioStream::TimerCallback(ptr_u dwUser)
1205 // dwUser contains ptr to AudioStream object
1206 AudioStream * pas = (AudioStream *) dwUser;
1208 return (pas->ServiceBuffer ());
1211 void AudioStream::Set_Byte_Cutoff(unsigned int byte_cutoff)
1213 if ( m_pwavefile == NULL )
1216 m_pwavefile->m_max_uncompressed_bytes_to_read = byte_cutoff;
1219 uint AudioStream::Get_Bytes_Committed(void)
1221 if (m_pwavefile == NULL) {
1225 return m_pwavefile->m_total_uncompressed_bytes_read;
1229 void AudioStream::Fade_and_Destroy()
1232 m_bDestroy_when_faded = true;
1236 void AudioStream::Fade_and_Stop()
1239 m_bDestroy_when_faded = false;
1243 void AudioStream::Stop(bool paused)
1247 alSourcePause(m_source_id);
1249 alSourceStop(m_source_id);
1250 alSourcei(m_source_id, AL_BUFFER, 0);
1255 m_bIsPaused = paused;
1257 // Delete Timer object
1258 m_timer.destructor();
1263 void AudioStream::Stop_and_Rewind()
1267 alSourceStop(m_source_id);
1268 alSourcei(m_source_id, AL_BUFFER, 0);
1271 // Delete Timer object
1272 m_timer.destructor();
1277 m_fCued = false; // this will cause wave file to start from beginning
1278 m_bReadingDone = false;
1282 void AudioStream::Set_Volume(float vol)
1285 alSourcef(m_source_id, AL_GAIN, vol);
1293 float AudioStream::Get_Volume()
1299 #define MAX_AUDIO_STREAMS 30
1300 static AudioStream *Audio_streams = NULL;
1303 void audiostream_init()
1305 if (Audiostream_inited) {
1309 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1310 // disk during a load/cue
1311 if (Wavedata_load_buffer == NULL) {
1312 Wavedata_load_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1314 if (Wavedata_load_buffer == NULL) {
1319 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1320 // disk during a service interval
1321 if (Wavedata_service_buffer == NULL) {
1322 Wavedata_service_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1324 if (Wavedata_service_buffer == NULL) {
1329 // Allocate memory for the buffer which holds the compressed wave data that is read from the hard disk
1330 if (Compressed_buffer == NULL) {
1331 Compressed_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1333 if (Compressed_buffer == NULL) {
1338 if (Compressed_service_buffer == NULL) {
1339 Compressed_service_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1341 if (Compressed_service_buffer == NULL) {
1346 if (Audio_streams == NULL) {
1347 Audio_streams = (AudioStream*)malloc(sizeof(AudioStream) * MAX_AUDIO_STREAMS);
1349 if (Audio_streams == NULL) {
1354 for (int i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1355 Audio_streams[i].Init_Data();
1356 Audio_streams[i].status = ASF_FREE;
1357 Audio_streams[i].type = ASF_NONE;
1360 Global_service_lock = SDL_CreateMutex();
1362 Audiostream_inited = 1;
1367 if (Wavedata_service_buffer) {
1368 free(Wavedata_service_buffer);
1369 Wavedata_service_buffer = NULL;
1372 if (Compressed_buffer) {
1373 free(Compressed_buffer);
1374 Compressed_buffer = NULL;
1377 if (Compressed_service_buffer) {
1378 free(Compressed_service_buffer);
1379 Compressed_service_buffer = NULL;
1382 if (Audio_streams) {
1383 free(Audio_streams);
1384 Audio_streams = NULL;
1387 Audiostream_inited = 0;
1390 // Close down the audiostream system. Must call audiostream_init() before any audiostream functions can
1392 void audiostream_close()
1394 if ( !Audiostream_inited ) {
1398 SDL_assert( Audio_streams != NULL );
1400 for (int i = 0; i < MAX_AUDIO_STREAMS; i++) {
1401 if ( Audio_streams[i].status == ASF_USED ) {
1402 Audio_streams[i].status = ASF_FREE;
1403 Audio_streams[i].Destroy();
1407 free(Audio_streams);
1408 Audio_streams = NULL;
1410 // free global buffers
1411 if (Wavedata_load_buffer) {
1412 free(Wavedata_load_buffer);
1413 Wavedata_load_buffer = NULL;
1416 if (Wavedata_service_buffer) {
1417 free(Wavedata_service_buffer);
1418 Wavedata_service_buffer = NULL;
1421 if (Compressed_buffer) {
1422 free(Compressed_buffer);
1423 Compressed_buffer = NULL;
1426 if (Compressed_service_buffer) {
1427 free(Compressed_service_buffer);
1428 Compressed_service_buffer = NULL;
1431 SDL_DestroyMutex( Global_service_lock );
1433 Audiostream_inited = 0;
1437 // Open a digital sound file for streaming
1439 // input: filename => disk filename of sound file
1440 // type => what type of audio stream do we want to open:
1445 // returns: success => handle to identify streaming sound
1447 int audiostream_open( const char *filename, int type )
1451 if ( !Audiostream_inited ) {
1455 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1456 if (Audio_streams[i].status == ASF_FREE) {
1457 Audio_streams[i].status = ASF_USED;
1458 Audio_streams[i].type = type;
1463 if (i == MAX_AUDIO_STREAMS) {
1464 nprintf(("Sound", "SOUND => No more audio streams available!\n"));
1471 Audio_streams[i].m_bits_per_sample_uncompressed = 8;
1474 case ASF_EVENTMUSIC:
1475 Audio_streams[i].m_bits_per_sample_uncompressed = 16;
1483 if ( !Audio_streams[i].Create(filename) ) {
1484 Audio_streams[i].status = ASF_FREE;
1491 void audiostream_close_file(int i, int fade)
1493 if ( !Audiostream_inited ) {
1501 SDL_assert( i < MAX_AUDIO_STREAMS );
1503 if (Audio_streams[i].status == ASF_FREE) {
1508 Audio_streams[i].Fade_and_Destroy();
1510 Audio_streams[i].Destroy();
1514 void audiostream_close_all(int fade)
1518 if ( !Audiostream_inited ) {
1522 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1523 if (Audio_streams[i].status == ASF_FREE) {
1527 audiostream_close_file(i, fade);
1531 void audiostream_play(int i, float volume, int looping)
1533 if ( !Audiostream_inited ) {
1541 SDL_assert( i < MAX_AUDIO_STREAMS );
1543 if (Audio_streams[i].status == ASF_FREE) {
1547 if (volume < 0.0f) {
1548 volume = Audio_streams[i].Get_Default_Volume();
1551 Audio_streams[i].Set_Default_Volume(volume);
1552 Audio_streams[i].Play(volume, looping);
1555 // use as buffer service function
1556 bool audiostream_is_playing(int i)
1558 if ( !Audiostream_inited ) {
1566 SDL_assert( i < MAX_AUDIO_STREAMS );
1568 if (Audio_streams[i].status == ASF_FREE) {
1572 return Audio_streams[i].Is_Playing();
1575 void audiostream_stop(int i, int rewind, int paused)
1577 if ( !Audiostream_inited ) {
1585 SDL_assert( i < MAX_AUDIO_STREAMS );
1587 if (Audio_streams[i].status == ASF_FREE) {
1592 Audio_streams[i].Stop_and_Rewind();
1594 Audio_streams[i].Stop( (paused != 0) );
1598 void audiostream_set_volume_all(float volume, int type)
1602 if ( !Audiostream_inited ) {
1606 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1607 if (Audio_streams[i].status == ASF_FREE) {
1611 if (Audio_streams[i].type == type) {
1612 Audio_streams[i].Set_Volume(volume);
1617 void audiostream_set_volume(int i, float volume)
1619 if ( !Audiostream_inited ) {
1627 SDL_assert( i < MAX_AUDIO_STREAMS );
1629 if (Audio_streams[i].status == ASF_FREE) {
1633 Audio_streams[i].Set_Volume(volume);
1636 bool audiostream_is_paused(int i)
1638 if ( !Audiostream_inited ) {
1646 SDL_assert( i < MAX_AUDIO_STREAMS );
1648 if (Audio_streams[i].status == ASF_FREE) {
1652 return Audio_streams[i].Is_Paused();
1655 void audiostream_set_byte_cutoff(int i, uint cutoff)
1657 if ( !Audiostream_inited ) {
1665 SDL_assert( i < MAX_AUDIO_STREAMS );
1667 if (Audio_streams[i].status == ASF_FREE) {
1671 Audio_streams[i].Set_Byte_Cutoff(cutoff);
1674 uint audiostream_get_bytes_committed(int i)
1676 if ( !Audiostream_inited ) {
1684 SDL_assert( i < MAX_AUDIO_STREAMS );
1686 if (Audio_streams[i].status == ASF_FREE) {
1690 return Audio_streams[i].Get_Bytes_Committed();
1693 bool audiostream_done_reading(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].Is_Past_Limit();
1712 int audiostream_is_inited()
1714 return Audiostream_inited;
1717 void audiostream_pause(int i)
1719 if ( !Audiostream_inited ) {
1727 SDL_assert( i < MAX_AUDIO_STREAMS );
1729 if (Audio_streams[i].status == ASF_FREE) {
1733 if ( audiostream_is_playing(i) ) {
1734 audiostream_stop(i, 0, 1);
1738 void audiostream_pause_all()
1742 if ( !Audiostream_inited ) {
1746 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1747 if (Audio_streams[i].status == ASF_FREE) {
1751 audiostream_pause(i);
1755 void audiostream_unpause(int i)
1759 if ( !Audiostream_inited ) {
1767 SDL_assert( i < MAX_AUDIO_STREAMS );
1769 if (Audio_streams[i].status == ASF_FREE) {
1773 if ( audiostream_is_paused(i) ) {
1774 is_looping = Audio_streams[i].Is_looping();
1775 audiostream_play(i, -1.0f, is_looping);
1779 void audiostream_unpause_all()
1783 if ( !Audiostream_inited ) {
1787 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1788 if (Audio_streams[i].status == ASF_FREE) {
1792 audiostream_unpause(i);