2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Sound/AudioStr.cpp $
15 * Routines to stream large WAV files from disk
18 * Revision 1.7 2005/03/29 02:18:47 taylor
19 * Various 64-bit platform fixes
20 * Fix compiler errors with MAKE_FS1 and fix gr_set_bitmap() too
21 * Make sure that turrets can fire at asteroids for FS1 (needed for a couple missions)
22 * Streaming audio support (big thanks to Pierre Willenbrock!!)
23 * Removed dependance on strings.tbl for FS1 since we don't actually need it now
25 * Revision 1.6 2003/08/03 16:10:30 taylor
26 * cleanup; compile warning fixes
28 * Revision 1.5 2002/06/09 04:41:26 relnev
29 * added copyright header
31 * Revision 1.4 2002/06/05 04:03:33 relnev
32 * finished cfilesystem.
34 * removed some old code.
36 * fixed mouse save off-by-one.
40 * Revision 1.3 2002/05/27 18:42:50 theoddone33
41 * Fix missing audiostr_* symbols
43 * Revision 1.2 2002/05/07 03:16:52 theoddone33
44 * The Great Newline Fix
46 * Revision 1.1.1.1 2002/05/03 03:28:10 root
50 * 5 9/14/99 1:32a Jimb
51 * Commented out Int3() that was hanging Jim's machine. Happens before
52 * sm2-07 command brief.
54 * 4 7/14/99 12:09p Jefff
55 * Make sure we're not servicing a bogus audiostream. Check for "used"
56 * after the critical section lock.
58 * 3 12/17/98 4:01p Andsager
59 * up wavedata buffer size to 180000 to allow stereo 16b/22KHz streaming
61 * 2 10/07/98 10:53a Dave
64 * 1 10/07/98 10:51a Dave
66 * 53 6/28/98 6:35p Lawrance
67 * move re-entrancy semaphore into audiostream class
69 * 52 5/24/98 4:42p Dan
70 * AL: Fix several bugs related to pausing and enabling/disabling event
73 * 51 5/21/98 11:57a Lawrance
74 * fix potential bug with transitions for music when in packfiles
76 * 50 5/15/98 9:09p Lawrance
77 * The last of the multi-threading fixes
79 * 49 5/15/98 7:57p Duncan
80 * AL: Fix race condition with music streaming
82 * 48 5/15/98 10:13a Lawrance
83 * remove unused audiostream member
85 * 47 5/14/98 5:45p Lawrance2
86 * Put critical section around audiostream destroying
88 * 46 5/12/98 5:40p Lawrance
89 * Add critical section code to the service buffer call.. since it is
90 * possible to release buffers while in this call
92 * 45 5/10/98 3:49p Sandeep
93 * Fix problem with having the audio streaming while trying to close down
96 * 44 4/30/98 4:53p John
97 * Restructured and cleaned up cfile code. Added capability to read off
98 * of CD-ROM drive and out of multiple pack files.
100 * 43 4/26/98 3:30a Lawrance
101 * Fix a couple of potential bugs
103 * 42 4/21/98 10:18a Dan
105 * 41 4/17/98 6:59a John
106 * Changed code the used 'new' and 'delete' to use 'malloc' and 'free'
107 * instead. Had to manually can constructors/destructors.
109 * 40 4/13/98 10:18a John
112 * 39 4/13/98 10:16a John
113 * Switched gettime back to timer_get_milliseconds, which is now thread
116 * 38 4/12/98 11:08p Lawrance
117 * switch back to using gettime() in separate threads
119 * 37 4/12/98 5:31p Lawrance
120 * use timer_get_milliseconds() instead of gettime()
122 * 36 4/06/98 12:36a Lawrance
123 * Ensure all non-music ADPCM files get decompressed to 8 bit.
125 * 35 4/03/98 4:56p Lawrance
126 * Upu the max audio streams to 30
128 * 34 3/31/98 4:50p Dan
129 * AL: Clean up all audio streams if necessary in
130 * event_music_level_close()
132 * 33 3/23/98 4:12p Lawrance
133 * Fix subtle bug with looping and fading out songs
135 * 32 2/18/98 5:49p Lawrance
136 * Even if the ADPCM codec is unavailable, allow game to continue.
138 * 31 2/15/98 4:43p Lawrance
139 * work on real-time voice
141 * 30 1/19/98 11:37p Lawrance
142 * Fixing Optimization build warnings
144 * 29 1/17/98 4:41p Lawrance
145 * Fix problem with multiple audio streams using the same buffers
147 * 28 1/16/98 11:49a Lawrance
148 * Use own internal timer for fading.
150 * 27 12/28/97 12:43p John
151 * Put in support for reading archive files; Made missionload use the
152 * cf_get_file_list function. Moved demos directory out of data tree.
154 * 26 12/27/97 8:08p Lawrance
155 * If an audiostream doesn't exists, it can't be playing
157 * 25 12/18/97 3:30p Lawrance
158 * Fix bug that sometimes caused music with no volume to not get stopped
161 * 24 12/17/97 10:17p Allender
162 * redid streadming code to use mmio* functions instead of cf* functions.
163 * Our functions are not reentrant!
165 * 23 12/10/97 10:04p Lawrance
166 * modify what happens in Audio_stream constructor
168 * 22 12/09/97 6:14p Lawrance
171 * 21 12/08/97 6:21p Lawrance
172 * fix problems with signaling that end-of-file has been reached
174 * 20 12/05/97 10:50a Lawrance
175 * improve how silence bytes are written on transitions
177 * 19 12/04/97 5:35p Lawrance
178 * fix bug that may have caused errors when writing silence
180 * 18 11/28/97 2:09p Lawrance
181 * Overhaul how ADPCM conversion works... use much less memory... safer
184 * 17 10/03/97 8:24a Lawrance
185 * When unpausing, be sure to retain looping status
187 * 16 9/24/97 5:30p Lawrance
188 * fix bug that was messing up streaming of 8 bit audio
190 * 15 9/18/97 10:31p Lawrance
191 * add functions to pause and unpause all audio streams
193 * 14 9/09/97 3:39p Sandeep
194 * warning level 4 bugs
206 #include <mmsystem.h>
221 #include "audiostr.h"
222 #include "cfile.h" // needed for cf_get_path
224 #include "sound.h" /* for Snd_sram */
231 #define OpenAL_ErrorCheck(onerr) do { \
232 int i = alGetError(); \
233 if (i != AL_NO_ERROR) { \
234 while(i != AL_NO_ERROR) { \
235 nprintf(("Warning", "%s/%s:%d - OpenAL error %s\n", __FUNCTION__, __FILE__, __LINE__, alGetString(i))); \
242 #define OpenAL_ErrorCheck(onerr)
249 #define LPBYTE BYTE *
251 static int audiostr_read_word(SDL_RWops *rw, WORD *i)
253 int rc = SDL_RWread( rw, i, 1, sizeof(WORD) );
255 if (rc != sizeof(WORD)) {
259 *i = INTEL_SHORT(*i);
264 static int audiostr_read_dword(SDL_RWops *rw, DWORD *i)
266 int rc = SDL_RWread( rw, i, 1, sizeof(DWORD) );
268 if (rc != sizeof(DWORD))
280 #define SUCCESS TRUE // Error returns for all member functions
281 #define FAILURE FALSE
284 typedef BOOL (*TIMERCALLBACK)(ptr_u);
286 #define BIGBUF_SIZE 180000 // This can be reduced to 88200 once we don't use any stereo
287 //#define BIGBUF_SIZE 88300 // This can be reduced to 88200 once we don't use any stereo
288 unsigned char *Wavedata_load_buffer = NULL; // buffer used for cueing audiostreams
289 unsigned char *Wavedata_service_buffer = NULL; // buffer used for servicing audiostreams
291 CRITICAL_SECTION Global_service_lock;
293 #define COMPRESSED_BUFFER_SIZE 88300
294 unsigned char *Compressed_buffer = NULL; // Used to load in compressed data during a cueing interval
295 unsigned char *Compressed_service_buffer = NULL; // Used to read in compressed data during a service interval
297 #define AS_HIGHEST_MAX 999999999 // max uncompressed filesize supported is 999 meg
303 // Wrapper class for Windows multimedia timer services. Provides
304 // both periodic and one-shot events. User must supply callback
305 // for periodic events.
311 void constructor(void);
312 void destructor(void);
313 BOOL Create (UINT nPeriod, UINT nRes, ptr_u dwUser, TIMERCALLBACK pfnCallback);
316 static void CALLBACK TimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
318 static Uint32 CALLBACK TimeProc(Uint32 interval, void *dwUser);
320 TIMERCALLBACK m_pfnCallback;
327 SDL_TimerID m_nIDTimer;
336 // WAV file class (read-only).
349 BOOL Open (LPSTR pszFilename);
351 int Read (BYTE * pbDest, UINT cbSize, int service=1);
352 UINT GetNumBytesRemaining (void) { return (m_nDataSize - m_nBytesPlayed); }
353 UINT GetUncompressedAvgDataRate (void) { return (m_nUncompressedAvgDataRate); }
354 UINT GetDataSize (void) { return (m_nDataSize); }
355 UINT GetNumBytesPlayed (void) { return (m_nBytesPlayed); }
356 BYTE GetSilenceData (void);
357 WAVEFORMATEX m_wfmt; // format of wave file used by Direct Sound
358 WAVEFORMATEX * m_pwfmt_original; // foramt of wave file from actual wave source
359 UINT m_total_uncompressed_bytes_read;
360 UINT m_max_uncompressed_bytes_to_read;
361 UINT m_bits_per_sample_uncompressed;
364 UINT m_data_offset; // number of bytes to actual wave data
365 int m_data_bytes_left;
372 UINT m_wave_format; // format of wave source (ie WAVE_FORMAT_PCM, WAVE_FORMAT_ADPCM)
373 UINT m_nBlockAlign; // wave data block alignment spec
374 UINT m_nUncompressedAvgDataRate; // average wave data rate
375 UINT m_nDataSize; // size of data chunk
376 UINT m_nBytesPlayed; // offset into data chunk
377 BOOL m_abort_next_read;
380 HACMSTREAM m_hStream;
382 WAVEFORMATEX m_wfxDest;
386 WAVEFORMATEX m_wfxDest;
392 // AudioStreamServices
394 // DirectSound apportions services on a per-window basis to allow
395 // sound from background windows to be muted. The AudioStreamServices
396 // class encapsulates the initialization of DirectSound services.
398 // Each window that wants to create AudioStream objects must
399 // first create and initialize an AudioStreamServices object.
400 // All AudioStream objects must be destroyed before the associated
401 // AudioStreamServices object is destroyed.
402 class AudioStreamServices
405 void Constructor(void);
408 LPDIRECTSOUND GetPDS (void) { return m_pds; }
417 // Audio stream interface class for playing WAV files using DirectSound.
418 // Users of this class must create AudioStreamServices object before
419 // creating an AudioStream object.
435 BOOL Create (LPSTR pszFilename, AudioStreamServices * pass);
437 void Play (long volume, int looping);
438 int Is_Playing(){ return(m_fPlaying); }
439 int Is_Paused(){ return(m_bIsPaused); }
440 int Is_Past_Limit() { return m_bPastLimit; }
441 void Stop (int paused=0);
442 void Stop_and_Rewind (void);
443 void Fade_and_Destroy (void);
444 void Fade_and_Stop(void);
445 void Set_Volume(long vol);
448 void Set_Byte_Cutoff(unsigned int num_bytes_cutoff);
449 void Set_Default_Volume(long converted_volume) { m_lDefaultVolume = converted_volume; }
450 long Get_Default_Volume() { return m_lDefaultVolume; }
451 unsigned int Get_Bytes_Committed(void);
452 int Is_looping() { return m_bLooping; }
455 UINT m_bits_per_sample_uncompressed;
459 BOOL WriteWaveData (UINT cbSize, UINT* num_bytes_written,int service=1);
460 BOOL WriteSilence (UINT cbSize);
461 DWORD GetMaxWriteSize (void);
462 BOOL ServiceBuffer (void);
463 static BOOL TimerCallback (ptr_u dwUser);
465 BOOL GetWritingDone (void);
468 AudioStreamServices * m_pass; // ptr to AudioStreamServices object
470 LPDIRECTSOUNDBUFFER m_pdsb; // ptr to Direct Sound buffer
472 ALuint m_al_multichannel_id; // name of openAL source
473 ALuint m_al_buffer_ids[MAX_AL_BUF]; //names of buffers
475 WaveFile * m_pwavefile; // ptr to WaveFile object
476 Timer m_timer; // ptr to Timer object
477 BOOL m_fCued; // semaphore (stream cued)
478 BOOL m_fPlaying; // semaphore (stream playing)
480 DSBUFFERDESC m_dsbd; // Direct Sound buffer description
482 LONG m_lInService; // reentrancy semaphore
483 UINT m_cbBufOffset; // last write position
484 UINT m_nBufLength; // length of sound buffer in msec
485 UINT m_cbBufSize; // size of sound buffer in bytes
486 UINT m_nBufService; // service interval in msec
487 UINT m_nTimeStarted; // time (in system time) playback started
489 BOOL m_bLooping; // whether or not to loop playback
490 BOOL m_bFade; // fade out music
491 BOOL m_bDestroy_when_faded;
492 LONG m_lVolume; // volume of stream ( 0 -> -10 000 )
493 LONG m_lCutoffVolume;
494 BOOL m_bIsPaused; // stream is stopped, but not rewinded
495 UINT m_silence_written; // number of bytes of silence written to buffer
496 UINT m_bReadingDone; // no more bytes to be read from disk, still have remaining buffer to play
497 DWORD m_fade_timer_id; // timestamp so we know when to start fade
498 DWORD m_finished_id; // timestamp so we know when we've played #bytes required
499 BOOL m_bPastLimit; // flag to show we've played past the number of bytes requred
500 LONG m_lDefaultVolume;
502 int m_al_buffer_play;
507 CRITICAL_SECTION write_lock;
511 // AudioStreamServices class implementation
513 ////////////////////////////////////////////////////////////
516 void AudioStreamServices::Constructor(void)
519 // Initialize member data
522 // It would seem to make sense to initialize DirectSound here,
523 // but because there could be an error, it's best done in a
524 // separate member function, ::Initialize.
530 extern LPDIRECTSOUND pDirectSound; // From Sound.cpp
535 BOOL AudioStreamServices::Initialize ()
538 BOOL fRtn = SUCCESS; // assume success
542 m_pds = pDirectSound;
552 // AudioStream class implementation
554 ////////////////////////////////////////////////////////////
556 // The following constants are the defaults for our streaming buffer operation.
557 const UINT DefBufferLength = 2000; // default buffer length in msec
558 const UINT DefBufferServiceInterval = 250; // default buffer service interval in msec
561 AudioStream::AudioStream (void)
564 InitializeCriticalSection( &write_lock );
566 write_lock = SDL_CreateMutex();
572 AudioStream::~AudioStream (void)
575 DeleteCriticalSection( &write_lock );
577 SDL_DestroyMutex( write_lock );
582 void AudioStream::Init_Data ()
588 m_bPastLimit = FALSE;
590 m_bDestroy_when_faded = FALSE;
592 m_lCutoffVolume = -10000;
594 m_silence_written = 0;
595 m_bReadingDone = FALSE;
601 memset(m_al_buffer_ids, 0, sizeof(m_al_buffer_ids));
602 m_al_multichannel_id = 0;
603 m_al_buffer_play = 0;
605 m_fPlaying = m_fCued = FALSE;
606 m_lInService = FALSE;
608 m_nBufLength = DefBufferLength;
610 m_nBufService = DefBufferServiceInterval;
615 BOOL AudioStream::Create (LPSTR pszFilename, AudioStreamServices * pass)
617 BOOL fRtn = SUCCESS; // assume success
625 if (pszFilename && m_pass) {
626 // Create a new WaveFile object
628 m_pwavefile = (WaveFile *)malloc(sizeof(WaveFile));
635 m_pwavefile->m_bits_per_sample_uncompressed = m_bits_per_sample_uncompressed;
636 if (m_pwavefile->Open (pszFilename)) {
637 // Calculate sound buffer size in bytes
639 // Buffer size is average data rate times length of buffer
640 // No need for buffer to be larger than wave data though
641 m_cbBufSize = (m_pwavefile->GetUncompressedAvgDataRate () * m_nBufLength) / 1000;
642 nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
643 // m_cbBufSize = (m_cbBufSize > m_pwavefile->GetDataSize ()) ? m_pwavefile->GetDataSize () : m_cbBufSize;
645 //nprintf(("Sound", "SOUND => average data rate = %d\n\r", m_pwavefile->GetUncompressedAvgDataRate ()));
646 //nprintf(("Sound", "SOUND => m_cbBufSize = %d\n\r", m_cbBufSize));
648 // Create sound buffer
650 memset (&m_dsbd, 0, sizeof (DSBUFFERDESC));
651 m_dsbd.dwSize = sizeof (DSBUFFERDESC);
652 m_dsbd.dwBufferBytes = m_cbBufSize;
653 m_dsbd.lpwfxFormat = &m_pwavefile->m_wfmt;
654 m_dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_LOCSOFTWARE;
656 hr = (m_pass->GetPDS ())->CreateSoundBuffer (&m_dsbd, &m_pdsb, NULL);
660 Snd_sram += m_cbBufSize;
663 // Error, unable to create DirectSound buffer
664 nprintf(("Sound", "SOUND => Error, unable to create DirectSound buffer\n\r"));
665 if (hr == DSERR_BADFORMAT) {
666 nprintf(("Sound", "SOUND => Bad format (probably ADPCM)\n\r"));
675 (m_pwavefile->m_wfmt.wBitsPerSample/8) *
676 m_pwavefile->m_wfmt.nChannels*
677 m_pwavefile->m_wfmt.nSamplesPerSec;
678 // nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
679 // Create sound buffer
680 alGenBuffers(MAX_AL_BUF, m_al_buffer_ids);
682 OpenAL_ErrorCheck(return FAILURE);
684 alGenSources(1, &m_al_multichannel_id);
686 OpenAL_ErrorCheck(return FAILURE);
688 alSourcef(m_al_multichannel_id,AL_ROLLOFF_FACTOR,0);
690 OpenAL_ErrorCheck(return FAILURE);
692 alSourcef(m_al_multichannel_id,AL_SOURCE_RELATIVE,AL_TRUE);
694 OpenAL_ErrorCheck(return FAILURE);
696 ALfloat posv[] = { 0,0,0 };
697 alSourcefv(m_al_multichannel_id,AL_POSITION,posv);
699 OpenAL_ErrorCheck(return FAILURE);
701 alSourcef(m_al_multichannel_id,AL_GAIN,1);
703 OpenAL_ErrorCheck(return FAILURE);
707 Snd_sram += m_cbBufSize;
711 // Error opening file
712 nprintf(("SOUND", "SOUND => Failed to open wave file: %s\n\r", pszFilename));
713 m_pwavefile->Close();
720 // Error, unable to create WaveFile object
721 nprintf(("Sound", "SOUND => Failed to create WaveFile object %s\n\r", pszFilename));
726 // Error, passed invalid parms
735 BOOL AudioStream::Destroy (void)
740 EnterCriticalSection(&write_lock);
742 SDL_LockMutex(write_lock);
748 // Release DirectSound buffer
753 Snd_sram -= m_cbBufSize;
756 alDeleteBuffers(MAX_AL_BUF,m_al_buffer_ids);
757 alDeleteSources(1,&m_al_multichannel_id);
760 // Delete WaveFile object
762 m_pwavefile->Close();
770 LeaveCriticalSection(&write_lock);
772 SDL_UnlockMutex(write_lock);
780 // Writes wave data to sound buffer. This is a helper method used by Create and
781 // ServiceBuffer; it's not exposed to users of the AudioStream class.
782 BOOL AudioStream::WriteWaveData (UINT size, UINT *num_bytes_written, int service)
786 LPBYTE lpbuf1 = NULL;
787 LPBYTE lpbuf2 = NULL;
790 DWORD dwbyteswritten1 = 0;
791 DWORD dwbyteswritten2 = 0;
794 unsigned char *uncompressed_wave_data;
796 *num_bytes_written = 0;
798 if ( size == 0 || m_bReadingDone ) {
803 if ( !m_pdsb || !m_pwavefile ) {
808 EnterCriticalSection(&Global_service_lock);
811 if ( (m_al_buffer_ids[0] == 0) || !m_pwavefile ) {
816 SDL_LockMutex(Global_service_lock);
821 uncompressed_wave_data = Wavedata_service_buffer;
823 uncompressed_wave_data = Wavedata_load_buffer;
826 int num_bytes_read = 0;
829 // Lock the sound buffer
830 hr = m_pdsb->Lock (m_cbBufOffset, size, (void**)(&lpbuf1), &dwsize1, (void**)(&lpbuf2), &dwsize2, 0);
832 // Write data to sound buffer. Because the sound buffer is circular, we may have to
833 // do two write operations if locked portion of buffer wraps around to start of buffer.
836 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, dwsize1+dwsize2,service);
838 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize ,service);
840 if ( num_bytes_read == -1 ) {
841 // means nothing left to read!
846 if ( num_bytes_read > 0 ) {
848 if ( (unsigned int)num_bytes_read > dwsize1 ) {
849 dwbyteswritten1 = dwsize1;
850 dwbyteswritten2 = num_bytes_read - dwsize1;
852 memcpy(lpbuf1, uncompressed_wave_data, dwsize1);
854 memcpy(lpbuf2, uncompressed_wave_data+dwsize1, num_bytes_read-dwsize1);
856 dwbyteswritten1 = num_bytes_read;
858 memcpy(lpbuf1, uncompressed_wave_data, num_bytes_read);
861 nprintf(("SOUND", "SOUND ==> Queueing %d bytes of Data\n", num_bytes_read));
862 // Lock the sound buffer
863 ALenum format = AL_FORMAT_MONO8;
865 if (m_pwavefile->m_wfmt.nChannels == 1) {
866 if (m_pwavefile->m_wfmt.wBitsPerSample == 8)
867 format = AL_FORMAT_MONO8;
868 else if (m_pwavefile->m_wfmt.wBitsPerSample == 16)
869 format = AL_FORMAT_MONO16;
870 } else if (m_pwavefile->m_wfmt.nChannels == 2) {
871 if (m_pwavefile->m_wfmt.wBitsPerSample == 8)
872 format = AL_FORMAT_STEREO8;
873 else if (m_pwavefile->m_wfmt.wBitsPerSample == 16)
874 format = AL_FORMAT_STEREO16;
879 alSourceUnqueueBuffers(m_al_multichannel_id,1,&bid);
883 alBufferData(m_al_buffer_ids[m_al_buffer_play],format,uncompressed_wave_data,num_bytes_read,m_pwavefile->m_wfmt.nSamplesPerSec);
885 OpenAL_ErrorCheck(return FAILURE);
887 alSourceQueueBuffers(m_al_multichannel_id,1,&m_al_buffer_ids[m_al_buffer_play]);
889 OpenAL_ErrorCheck(return FAILURE);
893 if (m_al_buffer_play>=MAX_AL_BUF)
894 m_al_buffer_play = 0;
896 m_cbBufOffset = (m_cbBufOffset + num_bytes_read) % m_cbBufSize;
897 *num_bytes_written = num_bytes_read;
902 // Update our buffer offset and unlock sound buffer
903 m_cbBufOffset = (m_cbBufOffset + dwbyteswritten1 + dwbyteswritten2) % m_cbBufSize;
904 *num_bytes_written = dwbyteswritten1 + dwbyteswritten2;
905 m_pdsb->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
908 // Error locking sound buffer
909 nprintf(("SOUND", "SOUND ==> Error, unable to lock sound buffer in AudioStr\n"));
916 LeaveCriticalSection(&Global_service_lock);
918 SDL_UnlockMutex(Global_service_lock);
929 // Writes silence to sound buffer. This is a helper method used by
930 // ServiceBuffer; it's not exposed to users of the AudioStream class.
931 BOOL AudioStream::WriteSilence (UINT size)
934 LPBYTE lpbuf1 = NULL;
935 LPBYTE lpbuf2 = NULL;
938 DWORD dwbyteswritten1 = 0;
939 DWORD dwbyteswritten2 = 0;
942 // Lock the sound buffer
943 hr = m_pdsb->Lock (m_cbBufOffset, size, (void**)(&lpbuf1), &dwsize1, (void**)(&lpbuf2), &dwsize2, 0);
946 // Get silence data for this file format. Although word sizes vary for different
947 // wave file formats, ::Lock will always return pointers on word boundaries.
948 // Because silence data for 16-bit PCM formats is 0x0000 or 0x00000000, we can
949 // get away with writing bytes and ignoring word size here.
950 BYTE bSilence = m_pwavefile->GetSilenceData ();
952 // Write silence to sound buffer. Because the sound buffer is circular, we may have to
953 // do two write operations if locked portion of buffer wraps around to start of buffer.
954 memset (lpbuf1, bSilence, dwsize1);
955 dwbyteswritten1 = dwsize1;
957 // Second write required?
959 memset (lpbuf2, bSilence, dwsize2);
960 dwbyteswritten2 = dwsize2;
963 // Update our buffer offset and unlock sound buffer
964 m_cbBufOffset = (m_cbBufOffset + dwbyteswritten1 + dwbyteswritten2) % m_cbBufSize;
965 // m_pdsb->Unlock (lpbuf1, dwbyteswritten1, lpbuf2, dwbyteswritten2);
966 m_pdsb->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
969 // Error locking sound buffer
970 nprintf(("SOUND", "SOUND ==> Error, unable to lock sound buffer in AudioStr\n"));
982 // Helper function to calculate max size of sound buffer write operation, i.e. how much
983 // free space there is in buffer.
984 DWORD AudioStream::GetMaxWriteSize (void)
987 DWORD dwWriteCursor, dwPlayCursor, dwMaxSize;
989 // Get current play position
990 if (m_pdsb->GetCurrentPosition (&dwPlayCursor, &dwWriteCursor) == DS_OK) {
991 if (m_cbBufOffset <= dwPlayCursor) {
992 // Our write position trails play cursor
993 dwMaxSize = dwPlayCursor - m_cbBufOffset;
996 else {// (m_cbBufOffset > dw7Cursor)
997 // Play cursor has wrapped
998 dwMaxSize = m_cbBufSize - m_cbBufOffset + dwPlayCursor;
1002 // GetCurrentPosition call failed
1007 DWORD dwMaxSize = m_cbBufSize;
1010 alGetSourcei(m_al_multichannel_id,AL_BUFFERS_PROCESSED,&n);
1012 OpenAL_ErrorCheck(return 0);
1014 alGetSourcei(m_al_multichannel_id,AL_BUFFERS_QUEUED,&q);
1016 OpenAL_ErrorCheck(return 0);
1018 if (!n && q>=MAX_AL_BUF) //all buffers queued
1022 // nprintf(("Alan","Max write size: %d\n", dwMaxSize));
1029 // Helper function to check if all data is written
1030 BOOL AudioStream::GetWritingDone (void)
1034 alGetSourcei(m_al_multichannel_id,AL_BUFFERS_PROCESSED,&n);
1036 OpenAL_ErrorCheck(return 1);
1038 return (n == MAX_AL_BUF); //both buffers processed
1045 // Routine to service buffer requests initiated by periodic timer.
1047 // Returns TRUE if buffer serviced normally; otherwise returns FALSE.
1048 #define FADE_VOLUME_INTERVAL 400 // 100 == 1db
1049 #define VOLUME_ATTENUATION_BEFORE_CUTOFF 3000 // 12db
1050 BOOL AudioStream::ServiceBuffer (void)
1055 if ( status != ASF_USED )
1059 EnterCriticalSection(&write_lock);
1061 SDL_LockMutex(write_lock);
1064 // status may have changed, so lets check once again
1065 if ( status != ASF_USED ){
1067 LeaveCriticalSection(&write_lock);
1069 SDL_UnlockMutex(write_lock);
1074 // Check for reentrance
1076 if (InterlockedExchange (&m_lInService, TRUE) == FALSE) {
1078 if ( m_bFade == TRUE ) {
1079 if ( m_lCutoffVolume == -10000 ) {
1081 // nprintf(("Alan","Volume is: %d\n",vol));
1082 m_lCutoffVolume = max(vol - VOLUME_ATTENUATION_BEFORE_CUTOFF, -10000);
1086 vol = vol - FADE_VOLUME_INTERVAL; // decrease by 1db
1087 // nprintf(("Alan","Volume is now: %d\n",vol));
1090 // nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
1091 // nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
1092 if ( vol < m_lCutoffVolume ) {
1094 m_lCutoffVolume = -10000;
1095 if ( m_bDestroy_when_faded == TRUE ) {
1097 LeaveCriticalSection(&write_lock);
1099 SDL_UnlockMutex(write_lock);
1102 // Reset reentrancy semaphore
1104 InterlockedExchange (&m_lInService, FALSE);
1110 // Reset reentrancy semaphore
1112 LeaveCriticalSection(&write_lock);
1113 InterlockedExchange (&m_lInService, FALSE);
1115 SDL_UnlockMutex(write_lock);
1122 // All of sound not played yet, send more data to buffer
1123 DWORD dwFreeSpace = GetMaxWriteSize ();
1125 // Determine free space in sound buffer
1128 // Some wave data remains, but not enough to fill free space
1129 // Send wave data to buffer, fill remainder of free space with silence
1130 uint num_bytes_written;
1132 if (WriteWaveData (dwFreeSpace, &num_bytes_written) == SUCCESS) {
1133 // nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));
1135 if ( m_pwavefile->m_total_uncompressed_bytes_read >= m_pwavefile->m_max_uncompressed_bytes_to_read ) {
1136 m_fade_timer_id = timer_get_milliseconds() + 1700; // start fading 1.7 seconds from now
1137 m_finished_id = timer_get_milliseconds() + 2000; // 2 seconds left to play out buffer
1138 m_pwavefile->m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1141 if ( (m_fade_timer_id>0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
1142 m_fade_timer_id = 0;
1146 if ( (m_finished_id>0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
1148 m_bPastLimit = TRUE;
1152 if ( (num_bytes_written < dwFreeSpace) && m_bReadingDone ) {
1153 int num_bytes_silence;
1154 num_bytes_silence = dwFreeSpace - num_bytes_written;
1156 if ( num_bytes_silence > 0 ) {
1158 m_silence_written += num_bytes_silence;
1159 if (WriteSilence (num_bytes_silence) == FAILURE) {
1164 if ( m_silence_written >= m_cbBufSize ) {
1165 m_silence_written = 0;
1167 if ( m_bReadingDone && GetWritingDone()) {
1170 if ( m_bDestroy_when_faded == TRUE ) {
1172 LeaveCriticalSection(&write_lock);
1174 SDL_UnlockMutex(write_lock);
1177 // Reset reentrancy semaphore
1179 InterlockedExchange (&m_lInService, FALSE);
1184 // All of sound has played, stop playback or loop again
1185 if ( m_bLooping && !m_bFade) {
1186 Play(m_lVolume, m_bLooping);
1198 // Error writing wave data
1204 // Reset reentrancy semaphore
1205 InterlockedExchange (&m_lInService, FALSE);
1207 // Service routine reentered. Do nothing, just return
1211 LeaveCriticalSection(&write_lock);
1215 SDL_UnlockMutex(write_lock);
1222 void AudioStream::Cue (void)
1224 UINT num_bytes_written;
1228 m_fade_timer_id = 0;
1230 m_bPastLimit = FALSE;
1232 m_lCutoffVolume = -10000;
1234 m_bDestroy_when_faded = FALSE;
1239 // Reset file ptr, etc
1240 m_pwavefile->Cue ();
1243 // Reset DirectSound buffer
1244 m_pdsb->SetCurrentPosition (0);
1246 // Unqueue all buffers
1247 alSourceUnqueueBuffers(m_al_multichannel_id,MAX_AL_BUF,m_al_buffer_ids);
1250 // Fill buffer with wave data
1251 WriteWaveData (m_cbBufSize, &num_bytes_written,0);
1259 void AudioStream::Play (long volume, int looping)
1264 if (m_al_buffer_ids[0] != 0) {
1268 if ( m_bIsPaused == FALSE)
1272 // Cue for playback if necessary
1283 // Begin DirectSound playback
1284 HRESULT hr = m_pdsb->Play (0, 0, DSBPLAY_LOOPING);
1287 alSourcePlay(m_al_multichannel_id);
1289 OpenAL_ErrorCheck(return);
1291 m_nTimeStarted = timer_get_milliseconds();
1293 // Kick off timer to service buffer
1294 m_timer.constructor();
1296 m_timer.Create (m_nBufService, m_nBufService, ptr_u (this), TimerCallback);
1298 // Playback begun, no longer cued
1300 m_bIsPaused = FALSE;
1304 // If the buffer was lost, try to restore it
1305 if ( hr == DSERR_BUFFERLOST ) {
1306 hr = m_pdsb->Restore();
1307 if ( hr == DS_OK ) {
1308 hr = m_pdsb->Play (0, 0, DSBPLAY_LOOPING);
1311 nprintf(("Sound", "Sound => Lost a buffer, tried restoring but got %s\n", get_DSERR_text(hr) ));
1312 Int3(); // get Alan, he wants to see this
1316 if ( hr != DS_OK ) {
1317 nprintf(("Sound", "Sound => Play failed with return value %s\n", get_DSERR_text(hr) ));
1324 // Timer callback for Timer object created by ::Play method.
1325 BOOL AudioStream::TimerCallback (ptr_u dwUser)
1327 // dwUser contains ptr to AudioStream object
1328 AudioStream * pas = (AudioStream *) dwUser;
1330 return (pas->ServiceBuffer ());
1333 void AudioStream::Set_Byte_Cutoff(unsigned int byte_cutoff)
1335 if ( m_pwavefile == NULL )
1338 m_pwavefile->m_max_uncompressed_bytes_to_read = byte_cutoff;
1341 unsigned int AudioStream::Get_Bytes_Committed(void)
1343 if ( m_pwavefile == NULL )
1346 return m_pwavefile->m_total_uncompressed_bytes_read;
1351 void AudioStream::Fade_and_Destroy (void)
1354 m_bDestroy_when_faded = TRUE;
1358 void AudioStream::Fade_and_Stop (void)
1361 m_bDestroy_when_faded = FALSE;
1366 void AudioStream::Stop(int paused)
1369 // Stop DirectSound playback
1374 alSourcePause(m_al_multichannel_id);
1376 alSourceStop(m_al_multichannel_id);
1380 m_bIsPaused = paused;
1382 // Delete Timer object
1383 m_timer.destructor();
1388 void AudioStream::Stop_and_Rewind (void)
1391 // Stop DirectSound playback
1395 alSourceStop(m_al_multichannel_id);
1396 OpenAL_ErrorCheck(return);
1399 // Delete Timer object
1400 m_timer.destructor();
1405 m_fCued = FALSE; // this will cause wave file to start from beginning
1406 m_bReadingDone = FALSE;
1410 void AudioStream::Set_Volume(long vol)
1418 Assert( vol >= -10000 && vol <= 0 );
1421 h_result = m_pdsb->SetVolume(vol);
1423 ALfloat alvol = (vol != -10000) ? pow(10.0, (float)vol / (-600.0 / log10(.5))): 0.0;
1425 alSourcef(m_al_multichannel_id,AL_GAIN,alvol);
1431 if ( h_result != DS_OK )
1432 nprintf(("Sound","SOUND => SetVolume() failed with code '%s'\n", get_DSERR_text(h_result) ));
1438 long AudioStream::Get_Volume()
1444 void Timer::constructor(void)
1448 SDL_InitSubSystem(SDL_INIT_TIMER);
1454 void Timer::destructor(void)
1458 timeKillEvent (m_nIDTimer);
1460 SDL_RemoveTimer (m_nIDTimer);
1468 BOOL Timer::Create (UINT nPeriod, UINT nRes, ptr_u dwUser, TIMERCALLBACK pfnCallback)
1470 BOOL bRtn = SUCCESS; // assume success
1472 Assert(pfnCallback);
1473 Assert(nPeriod > 10);
1474 Assert(nPeriod >= nRes);
1476 m_nPeriod = nPeriod;
1479 m_pfnCallback = pfnCallback;
1482 if ((m_nIDTimer = timeSetEvent (m_nPeriod, m_nRes, TimeProc, (DWORD) this, TIME_PERIODIC)) == NULL) {
1484 if ((m_nIDTimer = SDL_AddTimer (m_nPeriod, TimeProc, (void*) this)) == NULL) {
1485 nprintf(("SOUND", "SOUND ==> Error, unable to create timer\n"));
1494 // Timer proc for multimedia timer callback set with timeSetTime().
1496 // Calls procedure specified when Timer object was created. The
1497 // dwUser parameter contains "this" pointer for associated Timer object.
1500 void CALLBACK Timer::TimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
1502 Uint32 CALLBACK Timer::TimeProc(Uint32 interval, void *dwUser)
1505 // dwUser contains ptr to Timer object
1506 Timer * ptimer = (Timer *) dwUser;
1508 // Call user-specified callback and pass back user specified data
1509 (ptimer->m_pfnCallback) (ptimer->m_dwUser);
1511 if (ptimer->m_nPeriod)
1514 SDL_RemoveTimer(ptimer->m_nIDTimer);
1515 ptimer->m_nIDTimer = NULL;
1522 // WaveFile class implementation
1524 ////////////////////////////////////////////////////////////
1527 void WaveFile::Init(void)
1529 // Init data members
1532 m_pwfmt_original = NULL;
1534 m_nUncompressedAvgDataRate = 0;
1537 m_total_uncompressed_bytes_read = 0;
1538 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1541 m_abort_next_read = FALSE;
1545 void WaveFile::Close(void)
1548 if (m_pwfmt_original) {
1549 free(m_pwfmt_original);
1550 m_pwfmt_original = NULL;
1553 if ( m_hStream_open ) {
1554 ACM_stream_close((void*)m_hStream);
1561 mmioClose( cfp, 0 );
1571 BOOL WaveFile::Open (LPSTR pszFilename)
1575 BOOL fRtn = SUCCESS; // assume success
1576 PCMWAVEFORMAT pcmwf;
1577 char fullpath[_MAX_PATH];
1579 m_total_uncompressed_bytes_read = 0;
1580 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1582 int FileSize, FileOffset;
1584 if ( !cf_find_file_location(pszFilename, CF_TYPE_ANY, fullpath, &FileSize, &FileOffset )) {
1589 cfp = mmioOpen(fullpath, NULL, MMIO_ALLOCBUF | MMIO_READ);
1591 cfp = SDL_RWFromFile(fullpath, "rb");
1594 if ( cfp == NULL ) {
1598 // Skip the "RIFF" tag and file size (8 bytes)
1599 // Skip the "WAVE" tag (4 bytes)
1601 mmioSeek( cfp, 12+FileOffset, SEEK_SET );
1603 SDL_RWseek( cfp, 12+FileOffset, SEEK_SET );
1605 // Now read RIFF tags until the end of file
1606 uint tag, size, next_chunk;
1608 while(done == FALSE) {
1610 if ( mmioRead(cfp, (char *)&tag, sizeof(uint)) != sizeof(uint) )
1612 if ( SDL_RWread(cfp, &tag, 1, sizeof(uint)) != sizeof(uint) )
1616 tag = INTEL_INT( tag );
1619 if ( mmioRead(cfp, (char *)&size, sizeof(uint)) != sizeof(uint) )
1621 if ( SDL_RWread(cfp, &size, 1, sizeof(uint)) != sizeof(uint) )
1625 size = INTEL_INT( size );
1628 next_chunk = mmioSeek( cfp, 0, SEEK_CUR );
1630 next_chunk = SDL_RWtell( cfp );
1635 case 0x20746d66: // The 'fmt ' tag
1637 mmioRead( cfp, (char *)&pcmwf, sizeof(PCMWAVEFORMAT) );
1638 if ( pcmwf.wf.wFormatTag != WAVE_FORMAT_PCM ) {
1639 mmioRead( cfp, (char *)&cbExtra, sizeof(short) );
1642 audiostr_read_word(cfp, &pcmwf.wf.wFormatTag);
1643 audiostr_read_word(cfp, &pcmwf.wf.nChannels);
1644 audiostr_read_dword(cfp, &pcmwf.wf.nSamplesPerSec);
1645 audiostr_read_dword(cfp, &pcmwf.wf.nAvgBytesPerSec);
1646 audiostr_read_word(cfp, &pcmwf.wf.nBlockAlign);
1647 audiostr_read_word(cfp, &pcmwf.wBitsPerSample);
1649 if ( pcmwf.wf.wFormatTag != WAVE_FORMAT_PCM ) {
1650 audiostr_read_word(cfp, &cbExtra);
1654 // Allocate memory for WAVEFORMATEX structure + extra bytes
1655 if ( (m_pwfmt_original = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){
1656 Assert(m_pwfmt_original != NULL);
1657 // Copy bytes from temporary format structure
1658 memcpy (m_pwfmt_original, &pcmwf, sizeof(pcmwf));
1659 m_pwfmt_original->cbSize = cbExtra;
1661 // Read those extra bytes, append to WAVEFORMATEX structure
1664 mmioRead( cfp, (char *)((ubyte *)(m_pwfmt_original) + sizeof(WAVEFORMATEX)), cbExtra );
1666 SDL_RWread( cfp, ((ubyte *)(m_pwfmt_original) + sizeof(WAVEFORMATEX)), 1, cbExtra );
1671 Int3(); // malloc failed
1676 case 0x61746164: // the 'data' tag
1677 m_nDataSize = size; // This is size of data chunk. Compressed if ADPCM.
1678 m_data_bytes_left = size;
1680 m_data_offset = mmioSeek( cfp, 0, SEEK_CUR);
1682 m_data_offset = SDL_RWtell( cfp );
1687 default: // unknown, skip it
1692 mmioSeek( cfp, next_chunk, SEEK_SET );
1694 SDL_RWseek( cfp, next_chunk, SEEK_SET );
1698 // At this stage, examine source format, and set up WAVEFORATEX structure for DirectSound.
1699 // Since DirectSound only supports PCM, force this structure to be PCM compliant. We will
1700 // need to convert data on the fly later if our souce is not PCM
1701 switch ( m_pwfmt_original->wFormatTag ) {
1702 case WAVE_FORMAT_PCM:
1703 m_wave_format = WAVE_FORMAT_PCM;
1704 m_wfmt.wBitsPerSample = m_pwfmt_original->wBitsPerSample;
1707 case WAVE_FORMAT_ADPCM:
1708 m_wave_format = WAVE_FORMAT_ADPCM;
1709 m_wfmt.wBitsPerSample = 16;
1710 m_bits_per_sample_uncompressed = 16;
1714 nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n"));
1721 // Set up the WAVEFORMATEX structure to have the right PCM characteristics
1722 m_wfmt.wFormatTag = WAVE_FORMAT_PCM;
1723 m_wfmt.nChannels = m_pwfmt_original->nChannels;
1724 m_wfmt.nSamplesPerSec = m_pwfmt_original->nSamplesPerSec;
1726 m_wfmt.nBlockAlign = (unsigned short)(( m_wfmt.nChannels * m_wfmt.wBitsPerSample ) / 8);
1727 m_wfmt.nAvgBytesPerSec = m_wfmt.nBlockAlign * m_wfmt.nSamplesPerSec;
1729 // Init some member data from format chunk
1730 m_nBlockAlign = m_pwfmt_original->nBlockAlign;
1731 m_nUncompressedAvgDataRate = m_wfmt.nAvgBytesPerSec;
1733 // Cue for streaming
1740 // Handle all errors here
1741 nprintf(("SOUND","SOUND ==> Could not open wave file %s for streaming\n",pszFilename));
1747 mmioClose( cfp, 0 );
1753 if (m_pwfmt_original)
1755 free(m_pwfmt_original);
1756 m_pwfmt_original = NULL;
1766 // Set the file pointer to the start of wave data
1768 BOOL WaveFile::Cue (void)
1770 BOOL fRtn = SUCCESS; // assume success
1773 m_total_uncompressed_bytes_read = 0;
1774 m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1777 rval = mmioSeek( cfp, m_data_offset, SEEK_SET );
1779 rval = SDL_RWseek( cfp, m_data_offset, SEEK_SET );
1785 m_data_bytes_left = m_nDataSize;
1786 m_abort_next_read = FALSE;
1794 // Returns number of bytes actually read.
1796 // Returns -1 if there is nothing more to be read. This function can return 0, since
1797 // sometimes the amount of bytes requested is too small for the ACM decompression to
1798 // locate a suitable block
1799 int WaveFile::Read(BYTE *pbDest, UINT cbSize, int service)
1801 unsigned char *dest_buf=NULL, *uncompressed_wave_data;
1802 int rc, uncompressed_bytes_written;
1803 unsigned int src_bytes_used, convert_len, num_bytes_desired=0, num_bytes_read;
1805 // nprintf(("Alan","Reqeusted: %d\n", cbSize));
1809 uncompressed_wave_data = Wavedata_service_buffer;
1811 uncompressed_wave_data = Wavedata_load_buffer;
1814 switch ( m_wave_format ) {
1815 case WAVE_FORMAT_PCM:
1816 num_bytes_desired = cbSize;
1820 case WAVE_FORMAT_ADPCM:
1821 if ( !m_hStream_open ) {
1822 if ( !ACM_stream_open(m_pwfmt_original, &m_wfxDest, (void**)&m_hStream, m_bits_per_sample_uncompressed) ) {
1830 num_bytes_desired = cbSize;
1833 dest_buf = Compressed_service_buffer;
1835 dest_buf = Compressed_buffer;
1838 if ( num_bytes_desired <= 0 ) {
1839 num_bytes_desired = 0;
1840 // nprintf(("Alan","No bytes required for ADPCM time interval\n"));
1842 num_bytes_desired = ACM_query_source_size((void*)m_hStream, cbSize);
1843 // nprintf(("Alan","Num bytes desired: %d\n", num_bytes_desired));
1848 nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n"));
1859 // read data from disk
1860 if ( m_data_bytes_left <= 0 ) {
1862 uncompressed_bytes_written = 0;
1866 if ( m_data_bytes_left > 0 && num_bytes_desired > 0 ) {
1869 if ( num_bytes_desired <= (unsigned int)m_data_bytes_left ) {
1870 num_bytes_read = num_bytes_desired;
1873 num_bytes_read = m_data_bytes_left;
1877 actual_read = mmioRead( cfp, (char *)dest_buf, num_bytes_read );
1879 actual_read = SDL_RWread( cfp, dest_buf, 1, num_bytes_read );
1881 if ( (actual_read <= 0) || (m_abort_next_read) ) {
1883 uncompressed_bytes_written = 0;
1887 if ( num_bytes_desired >= (unsigned int)m_data_bytes_left ) {
1888 m_abort_next_read = 1;
1891 num_bytes_read = actual_read;
1894 // convert data if necessary, to PCM
1895 if ( m_wave_format == WAVE_FORMAT_ADPCM ) {
1896 if ( num_bytes_read > 0 ) {
1897 rc = ACM_convert((void*)m_hStream, dest_buf, num_bytes_read, uncompressed_wave_data, BIGBUF_SIZE, &convert_len, &src_bytes_used);
1901 if ( convert_len == 0 ) {
1907 Assert(src_bytes_used <= num_bytes_read);
1908 if ( src_bytes_used < num_bytes_read ) {
1909 // seek back file pointer to reposition before unused source data
1911 mmioSeek(cfp, src_bytes_used - num_bytes_read, SEEK_CUR);
1913 SDL_RWseek( cfp, src_bytes_used - num_bytes_read, SEEK_CUR );
1917 // Adjust number of bytes left
1918 m_data_bytes_left -= src_bytes_used;
1919 m_nBytesPlayed += src_bytes_used;
1920 uncompressed_bytes_written = convert_len;
1922 // Successful read, keep running total of number of data bytes read
1926 // Successful read, keep running total of number of data bytes read
1927 // Adjust number of bytes left
1928 m_data_bytes_left -= num_bytes_read;
1929 m_nBytesPlayed += num_bytes_read;
1930 uncompressed_bytes_written = num_bytes_read;
1936 uncompressed_bytes_written = 0;
1939 m_total_uncompressed_bytes_read += uncompressed_bytes_written;
1940 // nprintf(("Alan","Read: %d\n", uncompressed_bytes_written));
1941 return (uncompressed_bytes_written);
1948 // Returns 8 bits of data representing silence for the Wave file format.
1950 // Since we are dealing only with PCM format, we can fudge a bit and take
1951 // advantage of the fact that for all PCM formats, silence can be represented
1952 // by a single byte, repeated to make up the proper word size. The actual size
1953 // of a word of wave data depends on the format:
1955 // PCM Format Word Size Silence Data
1956 // 8-bit mono 1 byte 0x80
1957 // 8-bit stereo 2 bytes 0x8080
1958 // 16-bit mono 2 bytes 0x0000
1959 // 16-bit stereo 4 bytes 0x00000000
1961 BYTE WaveFile::GetSilenceData (void)
1963 BYTE bSilenceData = 0;
1965 // Silence data depends on format of Wave file
1966 if (m_pwfmt_original) {
1967 if (m_wfmt.wBitsPerSample == 8) {
1968 // For 8-bit formats (unsigned, 0 to 255)
1969 // Packed DWORD = 0x80808080;
1970 bSilenceData = 0x80;
1972 else if (m_wfmt.wBitsPerSample == 16) {
1973 // For 16-bit formats (signed, -32768 to 32767)
1974 // Packed DWORD = 0x00000000;
1975 bSilenceData = 0x00;
1987 return (bSilenceData);
1992 AudioStreamServices * m_pass = NULL; // ptr to AudioStreamServices object
1994 #define MAX_AUDIO_STREAMS 30
1995 AudioStream Audio_streams[MAX_AUDIO_STREAMS];
1997 int Audiostream_inited = 0;
1999 void audiostream_init()
2001 if ( Audiostream_inited == 1 )
2006 if ( !ACM_is_inited() ) {
2010 // Create and initialize AudioStreamServices object.
2011 // This must be done once and only once for each window that uses
2012 // streaming services.
2013 m_pass = (AudioStreamServices *)malloc(sizeof(AudioStreamServices));
2016 m_pass->Constructor();
2017 m_pass->Initialize();
2019 if ( !pDirectSound ) {
2025 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
2026 // disk during a load/cue
2027 if ( Wavedata_load_buffer == NULL ) {
2028 Wavedata_load_buffer = (unsigned char*)malloc(BIGBUF_SIZE);
2029 Assert(Wavedata_load_buffer != NULL);
2032 // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
2033 // disk during a service interval
2034 if ( Wavedata_service_buffer == NULL ) {
2035 Wavedata_service_buffer = (unsigned char*)malloc(BIGBUF_SIZE);
2036 Assert(Wavedata_service_buffer != NULL);
2039 // Allocate memory for the buffer which holds the compressed wave data that is read from the hard disk
2040 if ( Compressed_buffer == NULL ) {
2041 Compressed_buffer = (unsigned char*)malloc(COMPRESSED_BUFFER_SIZE);
2042 Assert(Compressed_buffer != NULL);
2045 if ( Compressed_service_buffer == NULL ) {
2046 Compressed_service_buffer = (unsigned char*)malloc(COMPRESSED_BUFFER_SIZE);
2047 Assert(Compressed_service_buffer != NULL);
2050 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2051 Audio_streams[i].Init_Data();
2052 Audio_streams[i].status = ASF_FREE;
2053 Audio_streams[i].type = ASF_NONE;
2057 InitializeCriticalSection( &Global_service_lock );
2059 Global_service_lock = SDL_CreateMutex( );
2062 Audiostream_inited = 1;
2065 // Close down the audiostream system. Must call audiostream_init() before any audiostream functions can
2067 void audiostream_close()
2069 if ( Audiostream_inited == 0 )
2074 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2075 if ( Audio_streams[i].status == ASF_USED ) {
2076 Audio_streams[i].status = ASF_FREE;
2077 Audio_streams[i].Destroy();
2081 // Destroy AudioStreamServices object
2087 // free global buffers
2088 if ( Wavedata_load_buffer ) {
2089 free(Wavedata_load_buffer);
2090 Wavedata_load_buffer = NULL;
2093 if ( Wavedata_service_buffer ) {
2094 free(Wavedata_service_buffer);
2095 Wavedata_service_buffer = NULL;
2098 if ( Compressed_buffer ) {
2099 free(Compressed_buffer);
2100 Compressed_buffer = NULL;
2103 if ( Compressed_service_buffer ) {
2104 free(Compressed_service_buffer);
2105 Compressed_service_buffer = NULL;
2109 DeleteCriticalSection( &Global_service_lock );
2111 SDL_DestroyMutex( Global_service_lock );
2113 Audiostream_inited = 0;
2116 // Open a digital sound file for streaming
2118 // input: filename => disk filename of sound file
2119 // type => what type of audio stream do we want to open:
2124 // returns: success => handle to identify streaming sound
2126 int audiostream_open( char * filename, int type )
2130 if (!Audiostream_inited || !snd_is_inited())
2133 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2134 if ( Audio_streams[i].status == ASF_FREE ) {
2135 Audio_streams[i].status = ASF_USED;
2136 Audio_streams[i].type = type;
2141 if ( i == MAX_AUDIO_STREAMS ) {
2142 nprintf(("Sound", "SOUND => No more audio streams available!\n"));
2149 Audio_streams[i].m_bits_per_sample_uncompressed = 8;
2151 case ASF_EVENTMUSIC:
2152 Audio_streams[i].m_bits_per_sample_uncompressed = 16;
2159 rc = Audio_streams[i].Create(filename, m_pass);
2161 Audio_streams[i].status = ASF_FREE;
2169 void audiostream_close_file(int i, int fade)
2171 if (!Audiostream_inited)
2177 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2179 if ( Audio_streams[i].status == ASF_USED ) {
2180 if ( fade == TRUE ) {
2181 Audio_streams[i].Fade_and_Destroy();
2184 Audio_streams[i].Destroy();
2189 void audiostream_close_all(int fade)
2193 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2194 if ( Audio_streams[i].status == ASF_FREE )
2197 audiostream_close_file(i, fade);
2201 extern int ds_convert_volume(float volume);
2203 void audiostream_play(int i, float volume, int looping)
2205 if (!Audiostream_inited)
2211 Assert(looping >= 0);
2212 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2214 // convert from 0->1 to -10000->0 for volume
2215 int converted_volume;
2216 if ( volume == -1 ) {
2217 converted_volume = Audio_streams[i].Get_Default_Volume();
2220 Assert(volume >= 0.0f && volume <= 1.0f );
2221 converted_volume = ds_convert_volume(volume);
2224 Assert( Audio_streams[i].status == ASF_USED );
2225 Audio_streams[i].Set_Default_Volume(converted_volume);
2226 Audio_streams[i].Play(converted_volume, looping);
2229 void audiostream_stop(int i, int rewind, int paused)
2231 if (!Audiostream_inited) return;
2236 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2237 Assert( Audio_streams[i].status == ASF_USED );
2240 Audio_streams[i].Stop_and_Rewind();
2242 Audio_streams[i].Stop(paused);
2245 int audiostream_is_playing(int i)
2250 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2251 if ( Audio_streams[i].status != ASF_USED )
2254 return Audio_streams[i].Is_Playing();
2258 void audiostream_set_volume_all(float volume, int type)
2262 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2263 if ( Audio_streams[i].status == ASF_FREE )
2266 if ( Audio_streams[i].type == type ) {
2267 int converted_volume;
2268 converted_volume = ds_convert_volume(volume);
2269 Audio_streams[i].Set_Volume(converted_volume);
2275 void audiostream_set_volume(int i, float volume)
2280 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2281 Assert( volume >= 0 && volume <= 1);
2283 if ( Audio_streams[i].status == ASF_FREE )
2286 int converted_volume;
2287 converted_volume = ds_convert_volume(volume);
2288 Audio_streams[i].Set_Volume(converted_volume);
2292 int audiostream_is_paused(int i)
2297 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2298 if ( Audio_streams[i].status == ASF_FREE )
2302 is_paused = Audio_streams[i].Is_Paused();
2307 void audiostream_set_byte_cutoff(int i, unsigned int cutoff)
2312 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2313 Assert( cutoff > 0 );
2315 if ( Audio_streams[i].status == ASF_FREE )
2318 Audio_streams[i].Set_Byte_Cutoff(cutoff);
2322 unsigned int audiostream_get_bytes_committed(int i)
2327 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2329 if ( Audio_streams[i].status == ASF_FREE )
2332 unsigned int num_bytes_committed;
2333 num_bytes_committed = Audio_streams[i].Get_Bytes_Committed();
2334 return num_bytes_committed;
2337 int audiostream_done_reading(int i)
2342 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2344 if ( Audio_streams[i].status == ASF_FREE )
2348 done_reading = Audio_streams[i].Is_Past_Limit();
2349 return done_reading;
2353 int audiostream_is_inited()
2355 return Audiostream_inited;
2358 // pause a single audio stream, indentified by handle i.
2359 void audiostream_pause(int i)
2364 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2365 if ( Audio_streams[i].status == ASF_FREE )
2368 if ( audiostream_is_playing(i) == TRUE ) {
2369 audiostream_stop(i, 0, 1);
2373 // pause all audio streams that are currently playing.
2374 void audiostream_pause_all()
2378 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2379 if ( Audio_streams[i].status == ASF_FREE )
2382 audiostream_pause(i);
2386 // unpause the audio stream identified by handle i.
2387 void audiostream_unpause(int i)
2394 Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2395 if ( Audio_streams[i].status == ASF_FREE )
2398 if ( audiostream_is_paused(i) == TRUE ) {
2399 is_looping = Audio_streams[i].Is_looping();
2400 audiostream_play(i, -1.0f, is_looping);
2404 // unpause all audio streams that are currently paused
2405 void audiostream_unpause_all()
2409 for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2410 if ( Audio_streams[i].status == ASF_FREE )
2413 audiostream_unpause(i);