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)
80 #ifdef PLAT_UNIX // to end of file...
91 #define MAX_STREAM_BUFFERS 4
97 #define MAX_AUDIO_STREAMS 30
101 #define SUCCESS TRUE // Error returns for all member functions
102 #define FAILURE FALSE
105 #define BIGBUF_SIZE 180000 // This can be reduced to 88200 once we don't use any stereo
106 //#define BIGBUF_SIZE 88300 // This can be reduced to 88200 once we don't use any stereo
107 ubyte *Wavedata_load_buffer = NULL; // buffer used for cueing audiostreams
108 ubyte *Wavedata_service_buffer = NULL; // buffer used for servicing audiostreams
110 CRITICAL_SECTION Global_service_lock;
112 typedef BOOL (*TIMERCALLBACK)(ptr_u);
114 #define COMPRESSED_BUFFER_SIZE 88300
115 ubyte *Compressed_buffer = NULL; // Used to load in compressed data during a cueing interval
116 ubyte *Compressed_service_buffer = NULL; // Used to read in compressed data during a service interval
118 #define AS_HIGHEST_MAX 999999999 // max uncompressed filesize supported is 999 meg
121 int Audiostream_inited = 0;
124 static int audiostr_read_word(SDL_RWops *rw, WORD *i)
126 int rc = SDL_RWread( rw, i, 1, sizeof(WORD) );
128 if (rc != sizeof(WORD))
131 *i = INTEL_SHORT(*i);
136 static int audiostr_read_dword(SDL_RWops *rw, DWORD *i)
138 int rc = SDL_RWread( rw, i, 1, sizeof(DWORD) );
140 if (rc != sizeof(DWORD))
151 void constructor(void);
152 void destructor(void);
153 BOOL Create (UINT nPeriod, UINT nRes, DWORD dwUser, TIMERCALLBACK pfnCallback);
155 static Uint32 CALLBACK TimeProc(Uint32 interval, void *dwUser);
156 TIMERCALLBACK m_pfnCallback;
160 SDL_TimerID m_nIDTimer;
168 BOOL Open (const char *pszFilename);
170 int Read (ubyte *pbDest, uint cbSize, int service=1);
171 uint GetNumBytesRemaining (void) { return (m_nDataSize - m_nBytesPlayed); }
172 uint GetUncompressedAvgDataRate (void) { return (m_nUncompressedAvgDataRate); }
173 uint GetDataSize (void) { return (m_nDataSize); }
174 uint GetNumBytesPlayed (void) { return (m_nBytesPlayed); }
175 ubyte GetSilenceData (void);
176 WAVEFORMATEX m_wfmt; // format of wave file used by Direct Sound
177 WAVEFORMATEX *m_pwfmt_original; // foramt of wave file from actual wave source
178 uint m_total_uncompressed_bytes_read;
179 uint m_max_uncompressed_bytes_to_read;
180 uint m_bits_per_sample_uncompressed;
183 uint m_data_offset; // number of bytes to actual wave data
184 int m_data_bytes_left;
187 uint m_wave_format; // format of wave source (ie WAVE_FORMAT_PCM, WAVE_FORMAT_ADPCM)
188 uint m_nBlockAlign; // wave data block alignment spec
189 uint m_nUncompressedAvgDataRate; // average wave data rate
190 uint m_nDataSize; // size of data chunk
191 uint m_nBytesPlayed; // offset into data chunk
192 BOOL m_abort_next_read;
196 WAVEFORMATEX m_wfxDest;
204 BOOL Create (const char *pszFilename);
206 void Play (long volume, int looping);
207 int Is_Playing(){ return(m_fPlaying); }
208 int Is_Paused(){ return(m_bIsPaused); }
209 int Is_Past_Limit() { return m_bPastLimit; }
210 void Stop (int paused=0);
211 void Stop_and_Rewind (void);
212 void Fade_and_Destroy (void);
213 void Fade_and_Stop(void);
214 void Set_Volume(long vol);
217 void Set_Byte_Cutoff(unsigned int num_bytes_cutoff);
218 void Set_Default_Volume(long converted_volume) { m_lDefaultVolume = converted_volume; }
219 long Get_Default_Volume() { return m_lDefaultVolume; }
220 uint Get_Bytes_Committed(void);
221 int Is_looping() { return m_bLooping; }
224 ushort m_bits_per_sample_uncompressed;
228 BOOL WriteWaveData (uint cbSize, uint* num_bytes_written,int service=1);
229 BOOL WriteSilence (uint cbSize);
230 DWORD GetMaxWriteSize (void);
231 BOOL ServiceBuffer (void);
232 static BOOL TimerCallback (ptr_u dwUser);
234 ALuint m_source_id; // name of openAL source
235 ALuint m_buffer_ids[MAX_STREAM_BUFFERS]; //names of buffers
236 int m_play_buffer_id;
238 Timer m_timer; // ptr to Timer object
239 WaveFile * m_pwavefile; // ptr to WaveFile object
240 BOOL m_fCued; // semaphore (stream cued)
241 BOOL m_fPlaying; // semaphore (stream playing)
242 long m_lInService; // reentrancy semaphore
243 uint m_cbBufOffset; // last write position
244 uint m_nBufLength; // length of sound buffer in msec
245 uint m_cbBufSize; // size of sound buffer in bytes
246 uint m_nBufService; // service interval in msec
247 uint m_nTimeStarted; // time (in system time) playback started
249 BOOL m_bLooping; // whether or not to loop playback
250 BOOL m_bFade; // fade out music
251 BOOL m_bDestroy_when_faded;
252 long m_lVolume; // volume of stream ( 0 -> -10 000 )
253 long m_lCutoffVolume;
254 BOOL m_bIsPaused; // stream is stopped, but not rewinded
255 ushort m_silence_written; // number of bytes of silence written to buffer
256 ushort m_bReadingDone; // no more bytes to be read from disk, still have remaining buffer to play
257 DWORD m_fade_timer_id; // timestamp so we know when to start fade
258 DWORD m_finished_id; // timestamp so we know when we've played #bytes required
259 BOOL m_bPastLimit; // flag to show we've played past the number of bytes requred
260 long m_lDefaultVolume;
263 CRITICAL_SECTION write_lock;
267 // Timer class implementation
269 ////////////////////////////////////////////////////////////
272 void Timer::constructor(void)
279 void Timer::destructor(void)
282 SDL_RemoveTimer(m_nIDTimer);
288 BOOL Timer::Create (UINT nPeriod, UINT nRes, DWORD dwUser, TIMERCALLBACK pfnCallback)
290 BOOL bRtn = SUCCESS; // assume success
293 Assert(nPeriod > 10);
294 Assert(nPeriod >= nRes);
299 m_pfnCallback = pfnCallback;
301 if ((m_nIDTimer = SDL_AddTimer (m_nPeriod, TimeProc, (void*) this)) == NULL) {
302 nprintf(("SOUND", "SOUND ==> Error, unable to create timer\n"));
310 // Timer proc for multimedia timer callback set with timeSetTime().
312 // Calls procedure specified when Timer object was created. The
313 // dwUser parameter contains "this" pointer for associated Timer object.
315 Uint32 CALLBACK Timer::TimeProc(Uint32 interval, void *dwUser)
317 // dwUser contains ptr to Timer object
318 Timer * ptimer = (Timer *) dwUser;
320 // Call user-specified callback and pass back user specified data
321 (ptimer->m_pfnCallback) (ptimer->m_dwUser);
323 if (ptimer->m_nPeriod) {
326 SDL_RemoveTimer(ptimer->m_nIDTimer);
327 ptimer->m_nIDTimer = NULL;
333 // WaveFile class implementation
335 ////////////////////////////////////////////////////////////
338 void WaveFile::Init(void)
343 m_pwfmt_original = NULL;
345 m_nUncompressedAvgDataRate = 0;
348 m_total_uncompressed_bytes_read = 0;
349 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
352 m_abort_next_read = FALSE;
356 void WaveFile::Close(void)
359 if (m_pwfmt_original) {
360 free(m_pwfmt_original);
361 m_pwfmt_original = NULL;
364 if ( m_hStream_open ) {
365 ACM_stream_close((void*)m_hStream);
378 BOOL WaveFile::Open (const char *pszFilename)
382 BOOL fRtn = SUCCESS; // assume success
384 char fullpath[_MAX_PATH];
386 m_total_uncompressed_bytes_read = 0;
387 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
389 int FileSize, FileOffset;
391 if ( !cf_find_file_location(pszFilename, CF_TYPE_ANY, fullpath, &FileSize, &FileOffset )) {
395 cfp = SDL_RWFromFile(fullpath, "rb");
401 // Skip the "RIFF" tag and file size (8 bytes)
402 // Skip the "WAVE" tag (4 bytes)
403 SDL_RWseek( cfp, 12+FileOffset, SEEK_SET );
405 // Now read RIFF tags until the end of file
406 DWORD tag, size, next_chunk;
408 while(done == FALSE) {
409 if ( !audiostr_read_dword(cfp, &tag) )
412 if ( !audiostr_read_dword(cfp, &size) )
415 next_chunk = SDL_RWtell( cfp );
419 case 0x20746d66: // The 'fmt ' tag
420 audiostr_read_word(cfp, &pcmwf.wf.wFormatTag);
421 audiostr_read_word(cfp, &pcmwf.wf.nChannels);
422 audiostr_read_dword(cfp, &pcmwf.wf.nSamplesPerSec);
423 audiostr_read_dword(cfp, &pcmwf.wf.nAvgBytesPerSec);
424 audiostr_read_word(cfp, &pcmwf.wf.nBlockAlign);
425 audiostr_read_word(cfp, &pcmwf.wBitsPerSample);
427 if ( pcmwf.wf.wFormatTag != WAVE_FORMAT_PCM ) {
428 audiostr_read_word(cfp, &cbExtra);
431 // Allocate memory for WAVEFORMATEX structure + extra bytes
432 if ( (m_pwfmt_original = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){
433 Assert(m_pwfmt_original != NULL);
434 // Copy bytes from temporary format structure
435 memcpy (m_pwfmt_original, &pcmwf, sizeof(pcmwf));
436 m_pwfmt_original->cbSize = cbExtra;
438 // Read those extra bytes, append to WAVEFORMATEX structure
440 SDL_RWread( cfp, ((ubyte *)(m_pwfmt_original) + sizeof(WAVEFORMATEX)), 1, cbExtra );
444 Int3(); // malloc failed
449 case 0x61746164: // the 'data' tag
450 m_nDataSize = size; // This is size of data chunk. Compressed if ADPCM.
451 m_data_bytes_left = size;
452 m_data_offset = SDL_RWtell( cfp );
456 default: // unknown, skip it
460 SDL_RWseek( cfp, next_chunk, SEEK_SET );
463 // At this stage, examine source format, and set up WAVEFORATEX structure for DirectSound.
464 // Since DirectSound only supports PCM, force this structure to be PCM compliant. We will
465 // need to convert data on the fly later if our souce is not PCM
466 switch ( m_pwfmt_original->wFormatTag ) {
467 case WAVE_FORMAT_PCM:
468 m_wave_format = WAVE_FORMAT_PCM;
469 m_wfmt.wBitsPerSample = m_pwfmt_original->wBitsPerSample;
472 case WAVE_FORMAT_ADPCM:
473 m_wave_format = WAVE_FORMAT_ADPCM;
474 m_wfmt.wBitsPerSample = 16;
475 m_bits_per_sample_uncompressed = 16;
479 nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n", m_pwfmt_original->wFormatTag));
486 // Set up the WAVEFORMATEX structure to have the right PCM characteristics
487 m_wfmt.wFormatTag = WAVE_FORMAT_PCM;
488 m_wfmt.nChannels = m_pwfmt_original->nChannels;
489 m_wfmt.nSamplesPerSec = m_pwfmt_original->nSamplesPerSec;
491 m_wfmt.nBlockAlign = (ushort)(( m_wfmt.nChannels * m_wfmt.wBitsPerSample ) / 8);
492 m_wfmt.nAvgBytesPerSec = m_wfmt.nBlockAlign * m_wfmt.nSamplesPerSec;
494 // Init some member data from format chunk
495 m_nBlockAlign = m_pwfmt_original->nBlockAlign;
496 m_nUncompressedAvgDataRate = m_wfmt.nAvgBytesPerSec;
505 // Handle all errors here
506 nprintf(("SOUND","SOUND ==> Could not open wave file %s for streaming\n",pszFilename));
514 if (m_pwfmt_original)
516 free(m_pwfmt_original);
517 m_pwfmt_original = NULL;
526 // Set the file pointer to the start of wave data
528 BOOL WaveFile::Cue (void)
530 BOOL fRtn = SUCCESS; // assume success
533 m_total_uncompressed_bytes_read = 0;
534 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
536 rval = SDL_RWseek( cfp, m_data_offset, SEEK_SET );
542 m_data_bytes_left = m_nDataSize;
543 m_abort_next_read = FALSE;
551 // Returns number of bytes actually read.
553 // Returns -1 if there is nothing more to be read. This function can return 0, since
554 // sometimes the amount of bytes requested is too small for the ACM decompression to
555 // locate a suitable block
556 int WaveFile::Read(ubyte *pbDest, uint cbSize, int service)
558 void *dest_buf=NULL, *uncompressed_wave_data;
559 int rc, uncompressed_bytes_written;
560 uint src_bytes_used, convert_len, num_bytes_desired=0, num_bytes_read;
562 // nprintf(("Alan","Reqeusted: %d\n", cbSize));
565 uncompressed_wave_data = Wavedata_service_buffer;
567 uncompressed_wave_data = Wavedata_load_buffer;
570 switch ( m_wave_format ) {
571 case WAVE_FORMAT_PCM:
572 num_bytes_desired = cbSize;
576 case WAVE_FORMAT_ADPCM:
577 if ( !m_hStream_open ) {
578 if ( !ACM_stream_open(m_pwfmt_original, &m_wfxDest, (void**)&m_hStream, m_bits_per_sample_uncompressed) ) {
585 num_bytes_desired = cbSize;
588 dest_buf = Compressed_service_buffer;
590 dest_buf = Compressed_buffer;
593 if ( num_bytes_desired <= 0 ) {
594 num_bytes_desired = 0;
595 // nprintf(("Alan","No bytes required for ADPCM time interval\n"));
597 num_bytes_desired = ACM_query_source_size((void*)m_hStream, cbSize);
598 // nprintf(("Alan","Num bytes desired: %d\n", num_bytes_desired));
603 nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n"));
613 // read data from disk
614 if ( m_data_bytes_left <= 0 ) {
616 uncompressed_bytes_written = 0;
620 if ( (m_data_bytes_left > 0) && (num_bytes_desired > 0) ) {
623 if ( num_bytes_desired <= (uint)m_data_bytes_left ) {
624 num_bytes_read = num_bytes_desired;
627 num_bytes_read = m_data_bytes_left;
630 actual_read = SDL_RWread( cfp, dest_buf, 1, num_bytes_read );
632 if ( (actual_read <= 0) || (m_abort_next_read) ) {
634 uncompressed_bytes_written = 0;
638 if ( num_bytes_desired >= (uint)m_data_bytes_left ) {
639 m_abort_next_read = 1;
642 num_bytes_read = actual_read;
645 // convert data if necessary, to PCM
646 if ( m_wave_format == WAVE_FORMAT_ADPCM ) {
647 if ( num_bytes_read > 0 ) {
648 rc = ACM_convert((void*)m_hStream, (ubyte*)dest_buf, num_bytes_read, (ubyte*)uncompressed_wave_data, BIGBUF_SIZE, &convert_len, &src_bytes_used);
653 if ( convert_len == 0 ) {
658 Assert(src_bytes_used <= num_bytes_read);
659 if ( src_bytes_used < num_bytes_read ) {
660 // seek back file pointer to reposition before unused source data
661 SDL_RWseek( cfp, src_bytes_used - num_bytes_read, SEEK_CUR );
664 // Adjust number of bytes left
665 m_data_bytes_left -= src_bytes_used;
666 m_nBytesPlayed += src_bytes_used;
667 uncompressed_bytes_written = convert_len;
669 // Successful read, keep running total of number of data bytes read
673 // Successful read, keep running total of number of data bytes read
674 // Adjust number of bytes left
675 m_data_bytes_left -= num_bytes_read;
676 m_nBytesPlayed += num_bytes_read;
677 uncompressed_bytes_written = num_bytes_read;
678 #if BYTE_ORDER == BIG_ENDIAN
679 if ( m_wave_format == WAVE_FORMAT_PCM ) {
680 // swap 16-bit sound data
681 if (m_wfmt.wBitsPerSample == 16) {
684 for (int i=0; i<uncompressed_bytes_written; i=i+2) {
685 swap_tmp = (ushort*)((ubyte*)dest_buf + i);
686 *swap_tmp = INTEL_SHORT(*swap_tmp);
696 uncompressed_bytes_written = 0;
699 m_total_uncompressed_bytes_read += uncompressed_bytes_written;
700 // nprintf(("Alan","Read: %d\n", uncompressed_bytes_written));
701 return (uncompressed_bytes_written);
707 // Returns 8 bits of data representing silence for the Wave file format.
709 // Since we are dealing only with PCM format, we can fudge a bit and take
710 // advantage of the fact that for all PCM formats, silence can be represented
711 // by a single byte, repeated to make up the proper word size. The actual size
712 // of a word of wave data depends on the format:
714 // PCM Format Word Size Silence Data
715 // 8-bit mono 1 byte 0x80
716 // 8-bit stereo 2 bytes 0x8080
717 // 16-bit mono 2 bytes 0x0000
718 // 16-bit stereo 4 bytes 0x00000000
720 ubyte WaveFile::GetSilenceData (void)
722 ubyte bSilenceData = 0;
724 // Silence data depends on format of Wave file
725 if (m_pwfmt_original) {
726 if (m_wfmt.wBitsPerSample == 8) {
727 // For 8-bit formats (unsigned, 0 to 255)
728 // Packed DWORD = 0x80808080;
730 } else if (m_wfmt.wBitsPerSample == 16) {
731 // For 16-bit formats (signed, -32768 to 32767)
732 // Packed DWORD = 0x00000000;
741 return (bSilenceData);
745 // AudioStream class implementation
747 ////////////////////////////////////////////////////////////
749 // The following constants are the defaults for our streaming buffer operation.
750 const ushort DefBufferLength = 2000; // default buffer length in msec
751 const ushort DefBufferServiceInterval = 250; // default buffer service interval in msec
754 AudioStream::AudioStream (void)
756 SDL_LockMutex(write_lock);
760 AudioStream::~AudioStream (void)
762 SDL_UnlockMutex(write_lock);
765 void AudioStream::Init_Data ()
771 m_bPastLimit = FALSE;
773 m_bDestroy_when_faded = FALSE;
775 m_lCutoffVolume = -10000;
777 m_silence_written = 0;
778 m_bReadingDone = FALSE;
781 m_fPlaying = m_fCued = FALSE;
782 m_lInService = FALSE;
784 m_nBufLength = DefBufferLength;
786 m_nBufService = DefBufferServiceInterval;
789 memset(m_buffer_ids, 0, sizeof(m_buffer_ids));
791 m_play_buffer_id = 0;
795 BOOL AudioStream::Create (const char *pszFilename)
798 BOOL fRtn = SUCCESS; // assume success
805 // make 100% sure we got a good filename
806 if ( !strlen(pszFilename) )
809 // Create a new WaveFile object
810 m_pwavefile = (WaveFile *)malloc(sizeof(WaveFile));
817 m_pwavefile->m_bits_per_sample_uncompressed = m_bits_per_sample_uncompressed;
818 if (m_pwavefile->Open (pszFilename)) {
819 // Calculate sound buffer size in bytes
820 // Buffer size is average data rate times length of buffer
821 // No need for buffer to be larger than wave data though
822 m_cbBufSize = (m_nBufLength/1000) * (m_pwavefile->m_wfmt.wBitsPerSample/8) * m_pwavefile->m_wfmt.nChannels * m_pwavefile->m_wfmt.nSamplesPerSec;
823 m_cbBufSize /= MAX_STREAM_BUFFERS;
824 // if the requested buffer size is too big then cap it
825 m_cbBufSize = (m_cbBufSize > BIGBUF_SIZE) ? BIGBUF_SIZE : m_cbBufSize;
827 // nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
829 // Create sound buffer
830 OpenAL_ErrorCheck( alGenBuffers(MAX_STREAM_BUFFERS, m_buffer_ids), return FAILURE );
832 OpenAL_ErrorCheck( alGenSources(1, &m_source_id), return FAILURE );
834 OpenAL_ErrorPrint( alSourcef(m_source_id, AL_ROLLOFF_FACTOR, 0) );
836 OpenAL_ErrorPrint( alSourcei(m_source_id, AL_SOURCE_RELATIVE, AL_TRUE) );
838 ALfloat posv[] = { 0, 0, 0 };
839 OpenAL_ErrorPrint( alSourcefv(m_source_id, AL_POSITION, posv) );
841 OpenAL_ErrorPrint( alSourcef(m_source_id, AL_GAIN, 1) );
845 Snd_sram += m_cbBufSize;
848 // Error opening file
849 nprintf(("SOUND", "SOUND => Failed to open wave file: %s\n\r", pszFilename));
850 m_pwavefile->Close();
857 // Error, unable to create WaveFile object
858 nprintf(("Sound", "SOUND => Failed to create WaveFile object %s\n\r", pszFilename));
863 // Error, passed invalid parms
871 BOOL AudioStream::Destroy (void)
875 SDL_LockMutex(write_lock);
880 // Release sound buffer
881 OpenAL_ErrorPrint( alDeleteBuffers(MAX_STREAM_BUFFERS, m_buffer_ids) );
882 OpenAL_ErrorPrint( alDeleteSources(1, &m_source_id) );
883 Snd_sram -= m_cbBufSize;
885 // Delete WaveFile object
887 m_pwavefile->Close();
894 SDL_UnlockMutex(write_lock);
901 // Writes wave data to sound buffer. This is a helper method used by Create and
902 // ServiceBuffer; it's not exposed to users of the AudioStream class.
903 BOOL AudioStream::WriteWaveData (uint size, uint *num_bytes_written, int service)
906 ubyte *uncompressed_wave_data;
908 *num_bytes_written = 0;
910 if ( size == 0 || m_bReadingDone ) {
914 if ( (m_buffer_ids[0] == 0) || !m_pwavefile ) {
919 SDL_LockMutex(Global_service_lock);
923 uncompressed_wave_data = Wavedata_service_buffer;
925 uncompressed_wave_data = Wavedata_load_buffer;
928 int num_bytes_read = 0;
930 // Lock the sound buffer
931 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
933 if ( num_bytes_read == -1 ) {
934 // means nothing left to read!
939 if ( num_bytes_read > 0 ) {
940 // nprintf(("SOUND", "SOUND ==> Queueing %d bytes of Data\n", num_bytes_read));
942 // Lock the sound buffer
943 ALenum format = AL_FORMAT_MONO8;
945 if (m_pwavefile->m_wfmt.nChannels == 1) {
946 if (m_pwavefile->m_wfmt.wBitsPerSample == 8)
947 format = AL_FORMAT_MONO8;
948 else if (m_pwavefile->m_wfmt.wBitsPerSample == 16)
949 format = AL_FORMAT_MONO16;
950 } else if (m_pwavefile->m_wfmt.nChannels == 2) {
951 if (m_pwavefile->m_wfmt.wBitsPerSample == 8)
952 format = AL_FORMAT_STEREO8;
953 else if (m_pwavefile->m_wfmt.wBitsPerSample == 16)
954 format = AL_FORMAT_STEREO16;
957 // unqueue and recycle a processed buffer
961 OpenAL_ErrorPrint( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &p) );
964 OpenAL_ErrorPrint( alSourceUnqueueBuffers(m_source_id, 1, &bid) );
967 OpenAL_ErrorCheck( alBufferData(m_buffer_ids[m_play_buffer_id], format, uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.nSamplesPerSec), return FAILURE );
969 OpenAL_ErrorCheck( alSourceQueueBuffers(m_source_id, 1, &m_buffer_ids[m_play_buffer_id]), return FAILURE );
973 if (m_play_buffer_id >= MAX_STREAM_BUFFERS)
974 m_play_buffer_id = 0;
978 SDL_UnlockMutex(Global_service_lock);
987 // Writes silence to sound buffer. This is a helper method used by
988 // ServiceBuffer; it's not exposed to users of the AudioStream class.
989 BOOL AudioStream::WriteSilence (uint size)
993 // not used currently with the OpenAL code
1001 // Helper function to calculate max size of sound buffer write operation, i.e. how much
1002 // free space there is in buffer.
1003 DWORD AudioStream::GetMaxWriteSize (void)
1005 DWORD dwMaxSize = m_cbBufSize;
1008 OpenAL_ErrorCheck( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &n), return 0 );
1010 OpenAL_ErrorCheck( alGetSourcei(m_source_id, AL_BUFFERS_QUEUED, &q), return 0 );
1012 if (!n && (q >= MAX_STREAM_BUFFERS)) //all buffers queued
1015 // nprintf(("Alan","Max write size: %d\n", dwMaxSize));
1019 #define FADE_VOLUME_INTERVAL 400 // 100 == 1db
1020 #define VOLUME_ATTENUATION_BEFORE_CUTOFF 3000 // 12db
1021 BOOL AudioStream::ServiceBuffer (void)
1026 if ( status != ASF_USED )
1029 SDL_LockMutex(write_lock);
1031 // status may have changed, so lets check once again
1032 if ( status != ASF_USED ){
1033 SDL_UnlockMutex(write_lock);
1038 if ( m_bFade == TRUE ) {
1039 if ( m_lCutoffVolume == -10000 ) {
1041 // nprintf(("Alan","Volume is: %d\n",vol));
1042 m_lCutoffVolume = max(vol - VOLUME_ATTENUATION_BEFORE_CUTOFF, -10000);
1046 vol = vol - FADE_VOLUME_INTERVAL; // decrease by 1db
1047 // nprintf(("Alan","Volume is now: %d\n",vol));
1050 // nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
1051 // nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
1052 if ( vol < m_lCutoffVolume ) {
1054 m_lCutoffVolume = -10000;
1055 if ( m_bDestroy_when_faded == TRUE ) {
1056 SDL_UnlockMutex(write_lock);
1059 // Reset reentrancy semaphore
1065 // Reset reentrancy semaphore
1066 SDL_UnlockMutex(write_lock);
1073 // All of sound not played yet, send more data to buffer
1074 DWORD dwFreeSpace = GetMaxWriteSize ();
1076 // Determine free space in sound buffer
1079 // Some wave data remains, but not enough to fill free space
1080 // Send wave data to buffer, fill remainder of free space with silence
1081 uint num_bytes_written;
1083 if (WriteWaveData (dwFreeSpace, &num_bytes_written) == SUCCESS) {
1084 // nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));
1086 if ( m_pwavefile->m_total_uncompressed_bytes_read >= m_pwavefile->m_max_uncompressed_bytes_to_read ) {
1087 m_fade_timer_id = timer_get_milliseconds() + 1700; // start fading 1.7 seconds from now
1088 m_finished_id = timer_get_milliseconds() + 2000; // 2 seconds left to play out buffer
1089 m_pwavefile->m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1092 if ( (m_fade_timer_id>0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
1093 m_fade_timer_id = 0;
1097 if ( (m_finished_id>0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
1099 m_bPastLimit = TRUE;
1103 // get the number of buffers processed to see if we're done
1104 OpenAL_ErrorCheck( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &n), return FALSE );
1106 if ( m_bReadingDone && (n == MAX_STREAM_BUFFERS) ) {
1107 if ( m_bDestroy_when_faded == TRUE ) {
1108 SDL_UnlockMutex(write_lock);
1111 // Reset reentrancy semaphore
1115 // All of sound has played, stop playback or loop again
1116 if ( m_bLooping && !m_bFade) {
1117 Play(m_lVolume, m_bLooping);
1125 // Error writing wave data
1132 SDL_UnlockMutex(write_lock);
1138 void AudioStream::Cue (void)
1140 uint num_bytes_written;
1144 m_fade_timer_id = 0;
1146 m_bPastLimit = FALSE;
1148 m_lCutoffVolume = -10000;
1150 m_bDestroy_when_faded = FALSE;
1155 // Reset file ptr, etc
1156 m_pwavefile->Cue ();
1158 // Unqueue all buffers
1160 OpenAL_ErrorPrint( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &p) );
1161 OpenAL_ErrorPrint( alSourceUnqueueBuffers(m_source_id, p, m_buffer_ids) );
1163 // Fill buffer with wave data
1164 WriteWaveData (m_cbBufSize, &num_bytes_written, 0);
1171 void AudioStream::Play (long volume, int looping)
1173 if (m_buffer_ids[0] != 0) {
1176 if ( m_bIsPaused == FALSE)
1180 // Cue for playback if necessary
1190 OpenAL_ErrorPrint( alSourcePlay(m_source_id) );
1192 m_nTimeStarted = timer_get_milliseconds();
1195 // Kick off timer to service buffer
1196 m_timer.constructor();
1198 m_timer.Create (m_nBufService, m_nBufService, ptr_u (this), TimerCallback);
1200 // Playback begun, no longer cued
1202 m_bIsPaused = FALSE;
1206 // Timer callback for Timer object created by ::Play method.
1207 BOOL AudioStream::TimerCallback (ptr_u dwUser)
1209 // dwUser contains ptr to AudioStream object
1210 AudioStream * pas = (AudioStream *) dwUser;
1212 return (pas->ServiceBuffer ());
1215 void AudioStream::Set_Byte_Cutoff(unsigned int byte_cutoff)
1217 if ( m_pwavefile == NULL )
1220 m_pwavefile->m_max_uncompressed_bytes_to_read = byte_cutoff;
1223 unsigned int AudioStream::Get_Bytes_Committed(void)
1225 if ( m_pwavefile == NULL )
1228 return m_pwavefile->m_total_uncompressed_bytes_read;
1233 void AudioStream::Fade_and_Destroy (void)
1236 m_bDestroy_when_faded = TRUE;
1240 void AudioStream::Fade_and_Stop (void)
1243 m_bDestroy_when_faded = FALSE;
1248 void AudioStream::Stop(int paused)
1252 OpenAL_ErrorPrint( alSourcePause(m_source_id) );
1254 OpenAL_ErrorPrint( alSourceStop(m_source_id) );
1258 m_bIsPaused = paused;
1260 // Delete Timer object
1261 m_timer.destructor();
1266 void AudioStream::Stop_and_Rewind (void)
1270 OpenAL_ErrorPrint( alSourceStop(m_source_id) );
1272 // Delete Timer object
1273 m_timer.destructor();
1278 m_fCued = FALSE; // this will cause wave file to start from beginning
1279 m_bReadingDone = FALSE;
1283 void AudioStream::Set_Volume(long vol)
1291 Assert( vol >= -10000 && vol <= 0 );
1293 ALfloat alvol = (vol != -10000) ? powf(10.0f, (float)vol / (-600.0f / log10f(.5f))): 0.0f;
1295 OpenAL_ErrorPrint( alSourcef(m_source_id, AL_GAIN, alvol) );
1298 if ( h_result != 0 )
1299 nprintf(("Sound","SOUND => SetVolume() failed with code '%s'\n", get_DSERR_text(h_result) ));
1304 long AudioStream::Get_Volume()
1311 AudioStream Audio_streams[MAX_AUDIO_STREAMS];
1314 void audiostream_init()
1318 if ( Audiostream_inited == 1 )
1321 if ( !ACM_is_inited() ) {
1325 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1326 // disk during a load/cue
1327 if ( Wavedata_load_buffer == NULL ) {
1328 Wavedata_load_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1329 Assert(Wavedata_load_buffer != NULL);
1332 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1333 // disk during a service interval
1334 if ( Wavedata_service_buffer == NULL ) {
1335 Wavedata_service_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1336 Assert(Wavedata_service_buffer != NULL);
1339 // Allocate memory for the buffer which holds the compressed wave data that is read from the hard disk
1340 if ( Compressed_buffer == NULL ) {
1341 Compressed_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1342 Assert(Compressed_buffer != NULL);
1345 if ( Compressed_service_buffer == NULL ) {
1346 Compressed_service_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1347 Assert(Compressed_service_buffer != NULL);
1350 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1351 Audio_streams[i].Init_Data();
1352 Audio_streams[i].status = ASF_FREE;
1353 Audio_streams[i].type = ASF_NONE;
1356 SDL_InitSubSystem(SDL_INIT_TIMER);
1358 Global_service_lock = SDL_CreateMutex();
1360 Audiostream_inited = 1;
1363 // Close down the audiostream system. Must call audiostream_init() before any audiostream functions can
1365 void audiostream_close()
1367 if ( Audiostream_inited == 0 )
1372 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1373 if ( Audio_streams[i].status == ASF_USED ) {
1374 Audio_streams[i].status = ASF_FREE;
1375 Audio_streams[i].Destroy();
1379 // free global buffers
1380 if ( Wavedata_load_buffer ) {
1381 free(Wavedata_load_buffer);
1382 Wavedata_load_buffer = NULL;
1385 if ( Wavedata_service_buffer ) {
1386 free(Wavedata_service_buffer);
1387 Wavedata_service_buffer = NULL;
1390 if ( Compressed_buffer ) {
1391 free(Compressed_buffer);
1392 Compressed_buffer = NULL;
1395 if ( Compressed_service_buffer ) {
1396 free(Compressed_service_buffer);
1397 Compressed_service_buffer = NULL;
1400 SDL_DestroyMutex( Global_service_lock );
1402 Audiostream_inited = 0;
1406 // Open a digital sound file for streaming
1408 // input: filename => disk filename of sound file
1409 // type => what type of audio stream do we want to open:
1414 // returns: success => handle to identify streaming sound
1416 int audiostream_open( const char *filename, int type )
1420 if (!Audiostream_inited || !snd_is_inited())
1423 for ( i=0; i<MAX_AUDIO_STREAMS; i++ ) {
1424 if ( Audio_streams[i].status == ASF_FREE ) {
1425 Audio_streams[i].status = ASF_USED;
1426 Audio_streams[i].type = type;
1431 if ( i == MAX_AUDIO_STREAMS ) {
1432 nprintf(("Sound", "SOUND => No more audio streams available!\n"));
1439 Audio_streams[i].m_bits_per_sample_uncompressed = 8;
1440 case ASF_EVENTMUSIC:
1441 Audio_streams[i].m_bits_per_sample_uncompressed = 16;
1448 rc = Audio_streams[i].Create(filename);
1451 Audio_streams[i].status = ASF_FREE;
1458 void audiostream_close_file(int i, int fade)
1460 if (!Audiostream_inited)
1466 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1468 if ( Audio_streams[i].status == ASF_USED ) {
1469 if ( fade == TRUE ) {
1470 Audio_streams[i].Fade_and_Destroy();
1472 Audio_streams[i].Destroy();
1478 void audiostream_close_all(int fade)
1482 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1483 if ( Audio_streams[i].status == ASF_FREE )
1486 audiostream_close_file(i, fade);
1490 void audiostream_play(int i, float volume, int looping)
1492 if (!Audiostream_inited)
1498 Assert(looping >= 0);
1499 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1501 // convert from 0->1 to -10000->0 for volume
1502 int converted_volume;
1503 if ( volume == -1 ) {
1504 converted_volume = Audio_streams[i].Get_Default_Volume();
1507 Assert(volume >= 0.0f && volume <= 1.0f );
1508 converted_volume = ds_convert_volume(volume);
1511 Assert( Audio_streams[i].status == ASF_USED );
1512 Audio_streams[i].Set_Default_Volume(converted_volume);
1513 Audio_streams[i].Play(converted_volume, looping);
1516 // use as buffer service function
1517 int audiostream_is_playing(int i)
1522 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1523 if ( Audio_streams[i].status != ASF_USED )
1526 return Audio_streams[i].Is_Playing();
1529 void audiostream_stop(int i, int rewind, int paused)
1531 if (!Audiostream_inited)
1537 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1538 Assert( Audio_streams[i].status == ASF_USED );
1541 Audio_streams[i].Stop_and_Rewind();
1543 Audio_streams[i].Stop(paused);
1546 void audiostream_set_volume_all(float volume, int type)
1550 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1551 if ( Audio_streams[i].status == ASF_FREE )
1554 if ( Audio_streams[i].type == type ) {
1555 int converted_volume;
1556 converted_volume = ds_convert_volume(volume);
1557 Audio_streams[i].Set_Volume(converted_volume);
1562 void audiostream_set_volume(int i, float volume)
1567 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1568 Assert( volume >= 0 && volume <= 1);
1570 if ( Audio_streams[i].status == ASF_FREE )
1573 int converted_volume;
1574 converted_volume = ds_convert_volume(volume);
1575 Audio_streams[i].Set_Volume(converted_volume);
1578 int audiostream_is_paused(int i)
1583 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1584 if ( Audio_streams[i].status == ASF_FREE )
1588 is_paused = Audio_streams[i].Is_Paused();
1593 void audiostream_set_byte_cutoff(int i, unsigned int cutoff)
1598 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1599 Assert( cutoff > 0 );
1601 if ( Audio_streams[i].status == ASF_FREE )
1604 Audio_streams[i].Set_Byte_Cutoff(cutoff);
1607 uint audiostream_get_bytes_committed(int i)
1612 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1614 if ( Audio_streams[i].status == ASF_FREE )
1617 uint num_bytes_committed;
1618 num_bytes_committed = Audio_streams[i].Get_Bytes_Committed();
1620 return num_bytes_committed;
1623 int audiostream_done_reading(int i)
1628 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1630 if ( Audio_streams[i].status == ASF_FREE )
1634 done_reading = Audio_streams[i].Is_Past_Limit();
1636 return done_reading;
1639 int audiostream_is_inited()
1641 return Audiostream_inited;
1644 void audiostream_pause(int i)
1649 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1650 if ( Audio_streams[i].status == ASF_FREE )
1653 if ( audiostream_is_playing(i) == TRUE ) {
1654 audiostream_stop(i, 0, 1);
1658 void audiostream_pause_all()
1662 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1663 if ( Audio_streams[i].status == ASF_FREE )
1666 audiostream_pause(i);
1670 void audiostream_unpause(int i)
1677 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1678 if ( Audio_streams[i].status == ASF_FREE )
1681 if ( audiostream_is_paused(i) == TRUE ) {
1682 is_looping = Audio_streams[i].Is_looping();
1683 audiostream_play(i, -1.0f, is_looping);
1687 void audiostream_unpause_all()
1691 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1692 if ( Audio_streams[i].status == ASF_FREE )
1695 audiostream_unpause(i);
1699 void audiostream_set_sample_cutoff(int i, uint cutoff)
1704 uint audiostream_get_samples_committed(int i)