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) {
645 uncompressed_bytes_written = 0;
650 if ( (m_data_bytes_left > 0) && (num_bytes_desired > 0) ) {
653 if (num_bytes_desired <= (uint)m_data_bytes_left) {
654 num_bytes_read = num_bytes_desired;
656 num_bytes_read = m_data_bytes_left;
659 actual_read = cfread(dest_buf, 1, num_bytes_read, cfp);
661 if ( (actual_read <= 0) || (m_abort_next_read) ) {
663 uncompressed_bytes_written = 0;
668 if (num_bytes_desired >= (uint)m_data_bytes_left) {
669 m_abort_next_read = 1;
672 num_bytes_read = actual_read;
675 // convert data if necessary, to PCM
676 if (m_wave_format == WAVE_FORMAT_ADPCM) {
677 if ( num_bytes_read > 0 ) {
678 rc = ACM_convert((void*)m_hStream, (ubyte*)dest_buf, num_bytes_read, (ubyte*)uncompressed_wave_data, BIGBUF_SIZE, &convert_len, &src_bytes_used);
684 if (convert_len == 0) {
689 SDL_assert( src_bytes_used <= num_bytes_read );
691 if (src_bytes_used < num_bytes_read) {
692 // seek back file pointer to reposition before unused source data
693 cfseek(cfp, src_bytes_used - num_bytes_read, CF_SEEK_CUR);
696 // Adjust number of bytes left
697 m_data_bytes_left -= src_bytes_used;
698 m_nBytesPlayed += src_bytes_used;
699 uncompressed_bytes_written = convert_len;
701 // Successful read, keep running total of number of data bytes read
704 // Successful read, keep running total of number of data bytes read
705 // Adjust number of bytes left
706 m_data_bytes_left -= num_bytes_read;
707 m_nBytesPlayed += num_bytes_read;
708 uncompressed_bytes_written = num_bytes_read;
710 #if BYTE_ORDER == BIG_ENDIAN
711 if (m_wave_format == WAVE_FORMAT_PCM) {
712 // swap 16-bit sound data
713 if (m_wfmt.bits_per_sample == 16) {
716 for (int i = 0; i < uncompressed_bytes_written; i = (i+2)) {
717 swap_tmp = (ushort*)((ubyte*)dest_buf + i);
718 *swap_tmp = INTEL_SHORT(*swap_tmp);
729 uncompressed_bytes_written = 0;
732 m_total_uncompressed_bytes_read += uncompressed_bytes_written;
733 // nprintf(("Alan","Read: %d\n", uncompressed_bytes_written));
735 return uncompressed_bytes_written;
740 // Returns 8 bits of data representing silence for the Wave file format.
742 // Since we are dealing only with PCM format, we can fudge a bit and take
743 // advantage of the fact that for all PCM formats, silence can be represented
744 // by a single byte, repeated to make up the proper word size. The actual size
745 // of a word of wave data depends on the format:
747 // PCM Format Word Size Silence Data
748 // 8-bit mono 1 byte 0x80
749 // 8-bit stereo 2 bytes 0x8080
750 // 16-bit mono 2 bytes 0x0000
751 // 16-bit stereo 4 bytes 0x00000000
753 ubyte WaveFile::GetSilenceData()
755 ubyte bSilenceData = 0;
757 // Silence data depends on format of Wave file
758 if (m_pwfmt_original) {
759 if (m_wfmt.bits_per_sample == 8) {
760 // For 8-bit formats (unsigned, 0 to 255)
761 // Packed DWORD = 0x80808080;
763 } else if (m_wfmt.bits_per_sample == 16) {
764 // For 16-bit formats (signed, -32768 to 32767)
765 // Packed DWORD = 0x00000000;
778 // AudioStream class implementation
780 ////////////////////////////////////////////////////////////
782 // The following constants are the defaults for our streaming buffer operation.
783 static const ushort DefBufferLength = 2000; // default buffer length in msec
784 static const ushort DefBufferServiceInterval = 250; // default buffer service interval in msec
787 AudioStream::AudioStream()
792 AudioStream::~AudioStream()
796 void AudioStream::Init_Data()
802 m_bPastLimit = false;
804 m_bDestroy_when_faded = false;
805 m_lDefaultVolume = 1.0f;
807 m_lCutoffVolume = 0.0f;
809 m_silence_written = 0;
810 m_bReadingDone = false;
814 m_fPlaying = m_fCued = false;
815 m_lInService = false;
817 m_nBufLength = DefBufferLength;
819 m_nBufService = DefBufferServiceInterval;
822 memset(m_buffer_ids, 0, sizeof(m_buffer_ids));
824 m_play_buffer_id = 0;
828 bool AudioStream::Create(const char *pszFilename)
830 SDL_assert( pszFilename != NULL );
834 if (pszFilename == NULL) {
838 // make 100% sure we got a good filename
839 if ( !strlen(pszFilename) ) {
843 // Create a new WaveFile object
844 m_pwavefile = (WaveFile *)malloc(sizeof(WaveFile));
845 SDL_assert( m_pwavefile != NULL );
847 if (m_pwavefile == NULL) {
848 nprintf(("Sound", "SOUND => Failed to create WaveFile object %s\n\r", pszFilename));
855 m_pwavefile->m_bits_per_sample_uncompressed = m_bits_per_sample_uncompressed;
858 if ( m_pwavefile->Open(pszFilename) ) {
859 // Calculate sound buffer size in bytes
860 // Buffer size is average data rate times length of buffer
861 // No need for buffer to be larger than wave data though
862 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;
863 m_cbBufSize /= MAX_STREAM_BUFFERS;
864 // if the requested buffer size is too big then cap it
865 m_cbBufSize = (m_cbBufSize > BIGBUF_SIZE) ? BIGBUF_SIZE : m_cbBufSize;
867 // nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
869 // Create sound buffer
870 alGenBuffers(MAX_STREAM_BUFFERS, m_buffer_ids);
872 Snd_sram += m_cbBufSize * MAX_STREAM_BUFFERS;
874 // Error opening file
875 nprintf(("SOUND", "SOUND => Failed to open wave file: %s\n\r", pszFilename));
877 m_pwavefile->Close();
889 bool AudioStream::Destroy()
894 // Release sound buffer
895 alDeleteBuffers(MAX_STREAM_BUFFERS, m_buffer_ids);
897 Snd_sram -= m_cbBufSize;
899 // Delete WaveFile object
901 m_pwavefile->Close();
914 // Writes wave data to sound buffer. This is a helper method used by Create and
915 // ServiceBuffer; it's not exposed to users of the AudioStream class.
916 bool AudioStream::WriteWaveData(uint size, uint *num_bytes_written, int service)
918 ubyte *uncompressed_wave_data;
920 *num_bytes_written = 0;
922 if ( (size == 0) || m_bReadingDone ) {
926 if ( (m_buffer_ids[0] == 0) || !m_pwavefile ) {
931 SDL_LockMutex(Global_service_lock);
935 uncompressed_wave_data = Wavedata_service_buffer;
937 uncompressed_wave_data = Wavedata_load_buffer;
940 int num_bytes_read = 0;
942 oal_check_for_errors("AudioStream::WriteWaveData() begin");
945 for (int ib = 0; ib < MAX_STREAM_BUFFERS; ib++) {
946 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
948 if (num_bytes_read < 0) {
950 } else if (num_bytes_read > 0) {
951 alBufferData(m_buffer_ids[ib], m_pwavefile->GetOALFormat(), uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.sample_rate);
952 alSourceQueueBuffers(m_source_id, 1, &m_buffer_ids[ib]);
953 *num_bytes_written += num_bytes_read;
957 ALint buffers_processed = 0;
958 ALuint buffer_id = 0;
960 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed);
962 while (buffers_processed) {
963 alSourceUnqueueBuffers(m_source_id, 1, &buffer_id);
965 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
967 if (num_bytes_read < 0) {
969 } else if (num_bytes_read > 0) {
970 alBufferData(buffer_id, m_pwavefile->GetOALFormat(), uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.sample_rate);
971 alSourceQueueBuffers(m_source_id, 1, &buffer_id);
972 *num_bytes_written += num_bytes_read;
979 oal_check_for_errors("AudioStream::WriteWaveData() end");
982 SDL_UnlockMutex(Global_service_lock);
990 // Helper function to calculate max size of sound buffer write operation, i.e. how much
991 // free space there is in buffer.
992 uint AudioStream::GetMaxWriteSize()
994 uint dwMaxSize = m_cbBufSize;
997 oal_check_for_errors("AudioStream::GetMaxWriteSize() begin");
999 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &n);
1001 alGetSourcei(m_source_id, AL_BUFFERS_QUEUED, &q);
1003 if ( !n && (q >= MAX_STREAM_BUFFERS) ) {
1004 //all buffers queued
1008 oal_check_for_errors("AudioStream::GetMaxWriteSize() end");
1010 // nprintf(("Alan","Max write size: %d\n", dwMaxSize));
1014 #define VOLUME_ATTENUATION_BEFORE_CUTOFF 0.03f // 12db
1015 #define VOLUME_ATTENUATION 0.65f
1017 bool AudioStream::ServiceBuffer()
1022 if (type == ASF_FREE) {
1027 if (m_lCutoffVolume == 0.0f) {
1029 // nprintf(("Alan","Volume is: %d\n",vol));
1030 m_lCutoffVolume = vol * VOLUME_ATTENUATION_BEFORE_CUTOFF;
1033 vol = Get_Volume() * VOLUME_ATTENUATION;
1034 // nprintf(("Alan","Volume is now: %d\n",vol));
1037 // nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
1038 // nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
1039 if (vol < m_lCutoffVolume) {
1041 m_lCutoffVolume = 0.0f;
1043 if (m_bDestroy_when_faded) {
1056 // All of sound not played yet, send more data to buffer
1057 uint dwFreeSpace = GetMaxWriteSize();
1059 // Determine free space in sound buffer
1061 // Some wave data remains, but not enough to fill free space
1062 // Send wave data to buffer, fill remainder of free space with silence
1063 uint num_bytes_written;
1065 if ( WriteWaveData(dwFreeSpace, &num_bytes_written) ) {
1066 // nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));
1068 if (m_pwavefile->m_total_uncompressed_bytes_read >= m_pwavefile->m_max_uncompressed_bytes_to_read) {
1069 m_fade_timer_id = timer_get_milliseconds() + 1700; // start fading 1.7 seconds from now
1070 m_finished_id = timer_get_milliseconds() + 2000; // 2 seconds left to play out buffer
1071 m_pwavefile->m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1074 if ( (m_fade_timer_id > 0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
1075 m_fade_timer_id = 0;
1079 if ( (m_finished_id > 0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
1081 m_bPastLimit = true;
1084 // see if we're done
1087 alGetSourcei(m_source_id, AL_SOURCE_STATE, &state);
1089 if ( m_bReadingDone && (state != AL_PLAYING) ) {
1090 if ( m_bDestroy_when_faded == true ) {
1092 // Reset reentrancy semaphore
1097 // All of sound has played, stop playback or loop again
1098 if ( m_bLooping && !m_bFade) {
1099 Play(m_lVolume, m_bLooping);
1105 // Error writing wave data
1115 void AudioStream::Cue()
1117 uint num_bytes_written;
1121 m_fade_timer_id = 0;
1123 m_bPastLimit = false;
1125 m_lCutoffVolume = 0.0f;
1127 m_bDestroy_when_faded = false;
1132 // Reset file ptr, etc
1135 // Unqueue all buffers
1136 ALint buffers_processed = 0;
1137 ALuint buffer_id = 0;
1139 alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &buffers_processed);
1141 while (buffers_processed) {
1142 alSourceUnqueueBuffers(m_source_id, 1, &buffer_id);
1144 buffers_processed--;
1147 // Fill buffer with wave data
1148 WriteWaveData(m_cbBufSize, &num_bytes_written, 0);
1155 void AudioStream::Play(float volume, int looping)
1157 if ( m_buffer_ids[0] ) {
1158 oal_check_for_errors("AudioStream::Play() begin");
1162 if ( m_bIsPaused == false)
1166 // get source id if we don't have one
1167 if ( !m_source_id ) {
1168 sound_channel *chan = oal_get_free_channel(1.0f, -1, SND_PRIORITY_MUST_PLAY);
1169 m_source_id = chan->source_id;
1172 // Cue for playback if necessary
1183 m_nTimeStarted = timer_get_milliseconds();
1186 // Kick off timer to service buffer
1187 m_timer.constructor();
1189 m_timer.Create(m_nBufService, (ptr_u)this, TimerCallback);
1191 alSourcef(m_source_id, AL_GAIN, m_lVolume);
1192 alSource3f(m_source_id, AL_POSITION, 0.0f, 0.0f, 0.0f);
1193 alSource3f(m_source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1194 alSource3f(m_source_id, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1195 alSourcef(m_source_id, AL_ROLLOFF_FACTOR, 0.0f);
1196 alSourcei(m_source_id, AL_SOURCE_RELATIVE, AL_TRUE);
1197 alSourcei(m_source_id, AL_LOOPING, AL_FALSE);
1199 alSourcePlay(m_source_id);
1201 // Playback begun, no longer cued
1203 m_bIsPaused = false;
1205 oal_check_for_errors("AudioStream::Play() end");
1209 // Timer callback for Timer object created by ::Play method.
1210 bool AudioStream::TimerCallback(ptr_u dwUser)
1212 // dwUser contains ptr to AudioStream object
1213 AudioStream * pas = (AudioStream *) dwUser;
1215 return (pas->ServiceBuffer ());
1218 void AudioStream::Set_Byte_Cutoff(unsigned int byte_cutoff)
1220 if ( m_pwavefile == NULL )
1223 m_pwavefile->m_max_uncompressed_bytes_to_read = byte_cutoff;
1226 uint AudioStream::Get_Bytes_Committed(void)
1228 if (m_pwavefile == NULL) {
1232 return m_pwavefile->m_total_uncompressed_bytes_read;
1236 void AudioStream::Fade_and_Destroy()
1239 m_bDestroy_when_faded = true;
1243 void AudioStream::Fade_and_Stop()
1246 m_bDestroy_when_faded = false;
1250 void AudioStream::Stop(bool paused)
1254 alSourcePause(m_source_id);
1256 alSourceStop(m_source_id);
1257 alSourcei(m_source_id, AL_BUFFER, 0);
1262 m_bIsPaused = paused;
1264 // Delete Timer object
1265 m_timer.destructor();
1270 void AudioStream::Stop_and_Rewind()
1274 alSourceStop(m_source_id);
1275 alSourcei(m_source_id, AL_BUFFER, 0);
1278 // Delete Timer object
1279 m_timer.destructor();
1284 m_fCued = false; // this will cause wave file to start from beginning
1285 m_bReadingDone = false;
1289 void AudioStream::Set_Volume(float vol)
1292 alSourcef(m_source_id, AL_GAIN, vol);
1300 float AudioStream::Get_Volume()
1306 #define MAX_AUDIO_STREAMS 30
1307 static AudioStream *Audio_streams = NULL;
1310 void audiostream_init()
1312 if (Audiostream_inited) {
1316 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1317 // disk during a load/cue
1318 if (Wavedata_load_buffer == NULL) {
1319 Wavedata_load_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1321 if (Wavedata_load_buffer == NULL) {
1326 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1327 // disk during a service interval
1328 if (Wavedata_service_buffer == NULL) {
1329 Wavedata_service_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1331 if (Wavedata_service_buffer == NULL) {
1336 // Allocate memory for the buffer which holds the compressed wave data that is read from the hard disk
1337 if (Compressed_buffer == NULL) {
1338 Compressed_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1340 if (Compressed_buffer == NULL) {
1345 if (Compressed_service_buffer == NULL) {
1346 Compressed_service_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1348 if (Compressed_service_buffer == NULL) {
1353 if (Audio_streams == NULL) {
1354 Audio_streams = (AudioStream*)malloc(sizeof(AudioStream) * MAX_AUDIO_STREAMS);
1356 if (Audio_streams == NULL) {
1361 for (int i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1362 Audio_streams[i].Init_Data();
1363 Audio_streams[i].status = ASF_FREE;
1364 Audio_streams[i].type = ASF_NONE;
1367 Global_service_lock = SDL_CreateMutex();
1369 Audiostream_inited = 1;
1374 if (Wavedata_service_buffer) {
1375 free(Wavedata_service_buffer);
1376 Wavedata_service_buffer = NULL;
1379 if (Compressed_buffer) {
1380 free(Compressed_buffer);
1381 Compressed_buffer = NULL;
1384 if (Compressed_service_buffer) {
1385 free(Compressed_service_buffer);
1386 Compressed_service_buffer = NULL;
1389 if (Audio_streams) {
1390 free(Audio_streams);
1391 Audio_streams = NULL;
1394 Audiostream_inited = 0;
1397 // Close down the audiostream system. Must call audiostream_init() before any audiostream functions can
1399 void audiostream_close()
1401 if ( !Audiostream_inited ) {
1405 SDL_assert( Audio_streams != NULL );
1407 for (int i = 0; i < MAX_AUDIO_STREAMS; i++) {
1408 if ( Audio_streams[i].status == ASF_USED ) {
1409 Audio_streams[i].status = ASF_FREE;
1410 Audio_streams[i].Destroy();
1414 free(Audio_streams);
1415 Audio_streams = NULL;
1417 // free global buffers
1418 if (Wavedata_load_buffer) {
1419 free(Wavedata_load_buffer);
1420 Wavedata_load_buffer = NULL;
1423 if (Wavedata_service_buffer) {
1424 free(Wavedata_service_buffer);
1425 Wavedata_service_buffer = NULL;
1428 if (Compressed_buffer) {
1429 free(Compressed_buffer);
1430 Compressed_buffer = NULL;
1433 if (Compressed_service_buffer) {
1434 free(Compressed_service_buffer);
1435 Compressed_service_buffer = NULL;
1438 SDL_DestroyMutex( Global_service_lock );
1440 Audiostream_inited = 0;
1444 // Open a digital sound file for streaming
1446 // input: filename => disk filename of sound file
1447 // type => what type of audio stream do we want to open:
1452 // returns: success => handle to identify streaming sound
1454 int audiostream_open( const char *filename, int type )
1458 if ( !Audiostream_inited ) {
1462 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1463 if (Audio_streams[i].status == ASF_FREE) {
1464 Audio_streams[i].status = ASF_USED;
1465 Audio_streams[i].type = type;
1470 if (i == MAX_AUDIO_STREAMS) {
1471 nprintf(("Sound", "SOUND => No more audio streams available!\n"));
1478 Audio_streams[i].m_bits_per_sample_uncompressed = 8;
1481 case ASF_EVENTMUSIC:
1482 Audio_streams[i].m_bits_per_sample_uncompressed = 16;
1490 if ( !Audio_streams[i].Create(filename) ) {
1491 Audio_streams[i].status = ASF_FREE;
1498 void audiostream_close_file(int i, int fade)
1500 if ( !Audiostream_inited ) {
1508 SDL_assert( i < MAX_AUDIO_STREAMS );
1510 if (Audio_streams[i].status == ASF_FREE) {
1515 Audio_streams[i].Fade_and_Destroy();
1517 Audio_streams[i].Destroy();
1521 void audiostream_close_all(int fade)
1525 if ( !Audiostream_inited ) {
1529 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1530 if (Audio_streams[i].status == ASF_FREE) {
1534 audiostream_close_file(i, fade);
1538 void audiostream_play(int i, float volume, int looping)
1540 if ( !Audiostream_inited ) {
1548 SDL_assert( i < MAX_AUDIO_STREAMS );
1550 if (Audio_streams[i].status == ASF_FREE) {
1554 if (volume < 0.0f) {
1555 volume = Audio_streams[i].Get_Default_Volume();
1558 Audio_streams[i].Set_Default_Volume(volume);
1559 Audio_streams[i].Play(volume, looping);
1562 // use as buffer service function
1563 bool audiostream_is_playing(int i)
1565 if ( !Audiostream_inited ) {
1573 SDL_assert( i < MAX_AUDIO_STREAMS );
1575 if (Audio_streams[i].status == ASF_FREE) {
1579 return Audio_streams[i].Is_Playing();
1582 void audiostream_stop(int i, int rewind, int paused)
1584 if ( !Audiostream_inited ) {
1592 SDL_assert( i < MAX_AUDIO_STREAMS );
1594 if (Audio_streams[i].status == ASF_FREE) {
1599 Audio_streams[i].Stop_and_Rewind();
1601 Audio_streams[i].Stop( (paused != 0) );
1605 void audiostream_set_volume_all(float volume, int type)
1609 if ( !Audiostream_inited ) {
1613 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1614 if (Audio_streams[i].status == ASF_FREE) {
1618 if (Audio_streams[i].type == type) {
1619 Audio_streams[i].Set_Volume(volume);
1624 void audiostream_set_volume(int i, float volume)
1626 if ( !Audiostream_inited ) {
1634 SDL_assert( i < MAX_AUDIO_STREAMS );
1636 if (Audio_streams[i].status == ASF_FREE) {
1640 Audio_streams[i].Set_Volume(volume);
1643 bool audiostream_is_paused(int i)
1645 if ( !Audiostream_inited ) {
1653 SDL_assert( i < MAX_AUDIO_STREAMS );
1655 if (Audio_streams[i].status == ASF_FREE) {
1659 return Audio_streams[i].Is_Paused();
1662 void audiostream_set_byte_cutoff(int i, uint cutoff)
1664 if ( !Audiostream_inited ) {
1672 SDL_assert( i < MAX_AUDIO_STREAMS );
1674 if (Audio_streams[i].status == ASF_FREE) {
1678 Audio_streams[i].Set_Byte_Cutoff(cutoff);
1681 uint audiostream_get_bytes_committed(int i)
1683 if ( !Audiostream_inited ) {
1691 SDL_assert( i < MAX_AUDIO_STREAMS );
1693 if (Audio_streams[i].status == ASF_FREE) {
1697 return Audio_streams[i].Get_Bytes_Committed();
1700 bool audiostream_done_reading(int i)
1702 if ( !Audiostream_inited ) {
1710 SDL_assert( i < MAX_AUDIO_STREAMS );
1712 if (Audio_streams[i].status == ASF_FREE) {
1716 return Audio_streams[i].Is_Past_Limit();
1719 int audiostream_is_inited()
1721 return Audiostream_inited;
1724 void audiostream_pause(int i)
1726 if ( !Audiostream_inited ) {
1734 SDL_assert( i < MAX_AUDIO_STREAMS );
1736 if (Audio_streams[i].status == ASF_FREE) {
1740 if ( audiostream_is_playing(i) ) {
1741 audiostream_stop(i, 0, 1);
1745 void audiostream_pause_all()
1749 if ( !Audiostream_inited ) {
1753 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1754 if (Audio_streams[i].status == ASF_FREE) {
1758 audiostream_pause(i);
1762 void audiostream_unpause(int i)
1766 if ( !Audiostream_inited ) {
1774 SDL_assert( i < MAX_AUDIO_STREAMS );
1776 if (Audio_streams[i].status == ASF_FREE) {
1780 if ( audiostream_is_paused(i) ) {
1781 is_looping = Audio_streams[i].Is_looping();
1782 audiostream_play(i, -1.0f, is_looping);
1786 void audiostream_unpause_all()
1790 if ( !Audiostream_inited ) {
1794 for (i = 0; i < MAX_AUDIO_STREAMS; i++) {
1795 if (Audio_streams[i].status == ASF_FREE) {
1799 audiostream_unpause(i);