]> icculus.org git repositories - taylor/freespace2.git/blob - src/sound/audiostr-openal.cpp
woorps!
[taylor/freespace2.git] / src / sound / audiostr-openal.cpp
1 /*
2  * $Logfile: $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * OpenAL based audio streaming
8  *
9  * $Log$
10  * Revision 1.2  2005/08/12 20:21:06  taylor
11  * woorps!
12  *
13  * Revision 1.1  2005/08/12 08:44:39  taylor
14  * import of FS2_Open audio code which is now *nix only, does not include windows or ogg support that FS2_Open has
15  *
16  * Revision 1.12  2005/06/24 19:36:49  taylor
17  * we only want to have m_data_offset be 0 for oggs since the seeking callback will account for the true offset
18  * only extern the one int we need for the -nosound speech fix rather than including the entire header
19  *
20  * Revision 1.11  2005/06/19 02:45:55  taylor
21  * OGG streaming fixes to get data reading right and avoid skipping
22  * properly handle seeking in OGG streams
23  * compiler warning fix in OpenAL builds
24  *
25  * Revision 1.10  2005/06/01 09:41:14  taylor
26  * bit of cleanup for audiostr-openal and fix a Windows-only enum error
27  * bunch of OGG related fixes for Linux and Windows (DirectSound and OpenAL), fixes audio related TBP 3.2 crashes
28  * gracefully handle OGG logical bitstream changes, shouldn't even load if there is more than 1
29  *
30  * Revision 1.9  2005/05/28 19:43:28  taylor
31  * debug message fixing
32  * a little bit of code clarity
33  *
34  * Revision 1.8  2005/05/24 03:11:38  taylor
35  * an extra bounds check in sound.cpp
36  * fix audiostr error when filename is !NULL but 0 in len might hit on SDL debug code
37  *
38  * Revision 1.7  2005/05/15 06:47:57  taylor
39  * don't let the ogg callbacks close the file handle on us, let us do it ourselves to keep things straight
40  *
41  * Revision 1.6  2005/05/13 23:09:28  taylor
42  * Ooops!  Added the wrong version of the streaming patch from Jens
43  *
44  * Revision 1.5  2005/05/12 17:47:57  taylor
45  * use vm_malloc(), vm_free(), vm_realloc(), vm_strdup() rather than system named macros
46  *   fixes various problems and is past time to make the switch
47  * fix a few streaming errors in OpenAL code (Jens Granseuer)
48  * temporary change to help deal with missing music in OpenAL Windows builds
49  * don't assert when si->data is NULL unless we really need to check (OpenAL only)
50  *
51  * Revision 1.4  2005/04/05 11:48:22  taylor
52  * remove acm-unix.cpp, replaced by acm-openal.cpp since it's properly cross-platform now
53  * better error handling for OpenAL functions
54  * Windows can now build properly with OpenAL
55  * extra check to make sure we don't try and use too many hardware bases sources
56  * fix memory error from OpenAL extension list in certain instances
57  *
58  * Revision 1.3  2005/04/01 07:33:08  taylor
59  * fix hanging on exit with OpenAL
60  * some better error handling on OpenAL init and make it more Windows friendly too
61  * basic 3d sound stuff for OpenAL, not working right yet
62  *
63  * Revision 1.2  2005/03/27 08:51:24  taylor
64  * this is what coding on an empty stomach will get you
65  *
66  * Revision 1.1  2005/03/27 05:48:58  taylor
67  * initial import of OpenAL streaming (many thanks to Pierre Willenbrock for the missing parts)
68  *
69  *
70  * $NoKeywords: $
71  */
72
73 #ifdef PLAT_UNIX        // to end of file...
74
75 #ifndef __APPLE__
76         #include <AL/al.h>
77         #include <AL/alc.h>
78         #include <AL/alut.h>
79 #else
80         #include "al.h"
81         #include "alc.h"
82         #include "alut.h"
83 #endif // !__APPLE__
84
85
86 #include "pstypes.h"
87 #include "audiostr.h"
88 #include "ds.h"
89 #include "acm.h"
90 #include "cfile.h"
91 #include "sound.h"
92 #include "timer.h"
93
94
95 #define MAX_STREAM_BUFFERS 4
96
97 // status
98 #define ASF_FREE        0
99 #define ASF_USED        1
100
101 #define MAX_AUDIO_STREAMS       30
102
103 // Constants
104 #ifndef SUCCESS
105 #define SUCCESS TRUE        // Error returns for all member functions
106 #define FAILURE FALSE
107 #endif // SUCCESS
108
109 #define BIGBUF_SIZE                                     180000                  // This can be reduced to 88200 once we don't use any stereo
110 //#define BIGBUF_SIZE                                   88300                   // This can be reduced to 88200 once we don't use any stereo
111 ubyte *Wavedata_load_buffer = NULL;             // buffer used for cueing audiostreams
112 ubyte *Wavedata_service_buffer = NULL;  // buffer used for servicing audiostreams
113
114 CRITICAL_SECTION Global_service_lock;
115
116 typedef BOOL (*TIMERCALLBACK)(ptr_u);
117
118 #define COMPRESSED_BUFFER_SIZE  88300
119 ubyte *Compressed_buffer = NULL;                                // Used to load in compressed data during a cueing interval
120 ubyte *Compressed_service_buffer = NULL;        // Used to read in compressed data during a service interval
121
122 #define AS_HIGHEST_MAX  999999999       // max uncompressed filesize supported is 999 meg
123
124
125 int Audiostream_inited = 0;
126
127
128 static int audiostr_read_word(SDL_RWops *rw, WORD *i)
129 {
130         int rc = SDL_RWread( rw, i, 1, sizeof(WORD) );
131
132         if (rc != sizeof(WORD))
133                 return 0;
134
135         *i = INTEL_SHORT(*i);
136
137         return 1;
138 }
139
140 static int audiostr_read_dword(SDL_RWops *rw, DWORD *i)
141 {
142         int rc = SDL_RWread( rw, i, 1, sizeof(DWORD) );
143
144         if (rc != sizeof(DWORD))
145                 return 0;
146
147         *i = INTEL_INT(*i);
148
149         return 1;
150 }
151
152 class Timer
153 {
154 public:
155     void constructor(void);
156     void destructor(void);
157     BOOL Create (UINT nPeriod, UINT nRes, DWORD dwUser,  TIMERCALLBACK pfnCallback);
158 protected:
159         static Uint32 CALLBACK TimeProc(Uint32 interval, void *dwUser);
160     TIMERCALLBACK m_pfnCallback;
161     DWORD m_dwUser;
162     UINT m_nPeriod;
163     UINT m_nRes;
164     SDL_TimerID m_nIDTimer;
165 };
166
167 class WaveFile
168 {
169 public:
170         void Init(void);
171         void Close(void);
172         BOOL Open (char *pszFilename);
173         BOOL Cue (void);
174         int     Read (ubyte *pbDest, uint cbSize, int service=1);
175         uint GetNumBytesRemaining (void) { return (m_nDataSize - m_nBytesPlayed); }
176         uint GetUncompressedAvgDataRate (void) { return (m_nUncompressedAvgDataRate); }
177         uint GetDataSize (void) { return (m_nDataSize); }
178         uint GetNumBytesPlayed (void) { return (m_nBytesPlayed); }
179         ubyte GetSilenceData (void);
180         WAVEFORMATEX m_wfmt;                                    // format of wave file used by Direct Sound
181         WAVEFORMATEX *m_pwfmt_original; // foramt of wave file from actual wave source
182         uint m_total_uncompressed_bytes_read;
183         uint m_max_uncompressed_bytes_to_read;
184         uint m_bits_per_sample_uncompressed;
185
186 protected:
187         uint m_data_offset;                                             // number of bytes to actual wave data
188         int  m_data_bytes_left;
189         SDL_RWops *cfp;
190
191         uint m_wave_format;                                             // format of wave source (ie WAVE_FORMAT_PCM, WAVE_FORMAT_ADPCM)
192         uint m_nBlockAlign;                                             // wave data block alignment spec
193         uint m_nUncompressedAvgDataRate;                // average wave data rate
194         uint m_nDataSize;                                                       // size of data chunk
195         uint m_nBytesPlayed;                                            // offset into data chunk
196         BOOL m_abort_next_read;
197
198         void                    *m_hStream;
199         int                             m_hStream_open;
200         WAVEFORMATEX    m_wfxDest;
201 };
202
203 class AudioStream
204 {
205 public:
206         AudioStream (void);
207         ~AudioStream (void);
208         BOOL Create (char *pszFilename);
209         BOOL Destroy (void);
210         void Play (long volume, int looping);
211         int Is_Playing(){ return(m_fPlaying); }
212         int Is_Paused(){ return(m_bIsPaused); }
213         int Is_Past_Limit() { return m_bPastLimit; }
214         void Stop (int paused=0);
215         void Stop_and_Rewind (void);
216         void Fade_and_Destroy (void);
217         void Fade_and_Stop(void);
218         void    Set_Volume(long vol);
219         long    Get_Volume();
220         void    Init_Data();
221         void    Set_Byte_Cutoff(unsigned int num_bytes_cutoff);
222         void  Set_Default_Volume(long converted_volume) { m_lDefaultVolume = converted_volume; }
223         long    Get_Default_Volume() { return m_lDefaultVolume; }
224         uint Get_Bytes_Committed(void);
225         int     Is_looping() { return m_bLooping; }
226         int     status;
227         int     type;
228         ushort m_bits_per_sample_uncompressed;
229
230 protected:
231         void Cue (void);
232         BOOL WriteWaveData (uint cbSize, uint* num_bytes_written,int service=1);
233         BOOL WriteSilence (uint cbSize);
234         DWORD GetMaxWriteSize (void);
235         BOOL ServiceBuffer (void);
236         static BOOL TimerCallback (ptr_u dwUser);
237
238         ALuint m_source_id;   // name of openAL source
239         ALuint m_buffer_ids[MAX_STREAM_BUFFERS]; //names of buffers
240         int m_play_buffer_id;
241
242         Timer m_timer;              // ptr to Timer object
243         WaveFile * m_pwavefile;        // ptr to WaveFile object
244         BOOL m_fCued;                  // semaphore (stream cued)
245         BOOL m_fPlaying;               // semaphore (stream playing)
246         long m_lInService;             // reentrancy semaphore
247         uint m_cbBufOffset;            // last write position
248         uint m_nBufLength;             // length of sound buffer in msec
249         uint m_cbBufSize;              // size of sound buffer in bytes
250         uint m_nBufService;            // service interval in msec
251         uint m_nTimeStarted;           // time (in system time) playback started
252
253         BOOL    m_bLooping;                                             // whether or not to loop playback
254         BOOL    m_bFade;                                                        // fade out music 
255         BOOL    m_bDestroy_when_faded;
256         long    m_lVolume;                                              // volume of stream ( 0 -> -10 000 )
257         long    m_lCutoffVolume;
258         BOOL    m_bIsPaused;                                    // stream is stopped, but not rewinded
259         ushort  m_silence_written;                      // number of bytes of silence written to buffer
260         ushort  m_bReadingDone;                         // no more bytes to be read from disk, still have remaining buffer to play
261         DWORD   m_fade_timer_id;                                // timestamp so we know when to start fade
262         DWORD   m_finished_id;                                  // timestamp so we know when we've played #bytes required
263         BOOL    m_bPastLimit;                                   // flag to show we've played past the number of bytes requred
264         long    m_lDefaultVolume;
265         int             h_result;
266
267         CRITICAL_SECTION write_lock;
268 };
269
270
271 // Timer class implementation
272 //
273 ////////////////////////////////////////////////////////////
274
275 // constructor
276 void Timer::constructor(void)
277 {
278         m_nIDTimer = NULL;
279 }
280
281
282 // Destructor
283 void Timer::destructor(void)
284 {
285         if (m_nIDTimer) {
286                 SDL_RemoveTimer(m_nIDTimer);
287                 m_nIDTimer = NULL;
288         }
289 }
290
291 // Create
292 BOOL Timer::Create (UINT nPeriod, UINT nRes, DWORD dwUser, TIMERCALLBACK pfnCallback)
293 {
294         BOOL bRtn = SUCCESS;    // assume success
295
296         Assert(pfnCallback);
297         Assert(nPeriod > 10);
298         Assert(nPeriod >= nRes);
299
300         m_nPeriod = nPeriod;
301         m_nRes = nRes;
302         m_dwUser = dwUser;
303         m_pfnCallback = pfnCallback;
304
305         if ((m_nIDTimer = SDL_AddTimer (m_nPeriod, TimeProc, (void*) this)) == NULL) {
306                 nprintf(("SOUND", "SOUND ==> Error, unable to create timer\n"));
307                 bRtn = FAILURE;
308         }
309
310         return (bRtn);
311 }
312
313
314 // Timer proc for multimedia timer callback set with timeSetTime().
315 //
316 // Calls procedure specified when Timer object was created. The 
317 // dwUser parameter contains "this" pointer for associated Timer object.
318 // 
319 Uint32 CALLBACK Timer::TimeProc(Uint32 interval, void *dwUser)
320 {
321     // dwUser contains ptr to Timer object
322         Timer * ptimer = (Timer *) dwUser;
323
324     // Call user-specified callback and pass back user specified data
325     (ptimer->m_pfnCallback) (ptimer->m_dwUser);
326
327     if (ptimer->m_nPeriod) {
328                 return interval;
329     } else {
330                 SDL_RemoveTimer(ptimer->m_nIDTimer);
331                 ptimer->m_nIDTimer = NULL;
332                 return 0;
333     }
334 }
335
336
337 // WaveFile class implementation
338 //
339 ////////////////////////////////////////////////////////////
340
341 // Constructor
342 void WaveFile::Init(void)
343 {
344         // Init data members
345         m_data_offset = 0;
346         cfp = NULL;
347         m_pwfmt_original = NULL;
348         m_nBlockAlign= 0;
349         m_nUncompressedAvgDataRate = 0;
350         m_nDataSize = 0;
351         m_nBytesPlayed = 0;
352         m_total_uncompressed_bytes_read = 0;
353         m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
354
355         m_hStream_open = 0;
356         m_abort_next_read = FALSE;
357 }
358
359 // Destructor
360 void WaveFile::Close(void)
361 {
362         // Free memory
363         if (m_pwfmt_original) {
364                 free(m_pwfmt_original);
365                 m_pwfmt_original = NULL;
366         }
367
368         if ( m_hStream_open ) {
369                 ACM_stream_close((void*)m_hStream);
370                 m_hStream_open = 0;
371         }
372
373         // Close file
374         if (cfp) {
375                 SDL_RWclose( cfp );
376                 cfp = NULL;
377         }
378 }
379
380
381 // Open
382 BOOL WaveFile::Open (char *pszFilename)
383 {
384         int done = FALSE;
385         WORD cbExtra = 0;
386         BOOL fRtn = SUCCESS;    // assume success
387         PCMWAVEFORMAT pcmwf;
388         char fullpath[_MAX_PATH];
389
390         m_total_uncompressed_bytes_read = 0;
391         m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
392
393         int FileSize, FileOffset;
394
395         if ( !cf_find_file_location(pszFilename, CF_TYPE_ANY, fullpath, &FileSize, &FileOffset ))       {
396                 goto OPEN_ERROR;
397         }
398
399         cfp = SDL_RWFromFile(fullpath, "rb");
400
401         if ( cfp == NULL ) {
402                 goto OPEN_ERROR;
403         }
404
405         // Skip the "RIFF" tag and file size (8 bytes)
406         // Skip the "WAVE" tag (4 bytes)
407         SDL_RWseek( cfp, 12+FileOffset, SEEK_SET );
408
409         // Now read RIFF tags until the end of file
410         uint tag, size, next_chunk;
411
412         while(done == FALSE)    {
413                 if ( !audiostr_read_dword(cfp, &tag) )
414                         break;
415
416                 if ( !audiostr_read_dword(cfp, &size) )
417                         break;
418
419                 next_chunk = SDL_RWtell( cfp );
420                 next_chunk += size;
421
422                 switch( tag )   {
423                 case 0x20746d66:                // The 'fmt ' tag
424                         audiostr_read_word(cfp, &pcmwf.wf.wFormatTag);
425                         audiostr_read_word(cfp, &pcmwf.wf.nChannels);
426                         audiostr_read_dword(cfp, &pcmwf.wf.nSamplesPerSec);
427                         audiostr_read_dword(cfp, &pcmwf.wf.nAvgBytesPerSec);
428                         audiostr_read_word(cfp, &pcmwf.wf.nBlockAlign);
429                         audiostr_read_word(cfp, &pcmwf.wBitsPerSample);
430
431                         if ( pcmwf.wf.wFormatTag != WAVE_FORMAT_PCM ) {
432                                 audiostr_read_word(cfp, &cbExtra);
433                         }
434
435                         // Allocate memory for WAVEFORMATEX structure + extra bytes
436                         if ( (m_pwfmt_original = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){
437                                 Assert(m_pwfmt_original != NULL);
438                                 // Copy bytes from temporary format structure
439                                 memcpy (m_pwfmt_original, &pcmwf, sizeof(pcmwf));
440                                 m_pwfmt_original->cbSize = cbExtra;
441
442                                 // Read those extra bytes, append to WAVEFORMATEX structure
443                                 if (cbExtra != 0) {
444                                         SDL_RWread( cfp, ((ubyte *)(m_pwfmt_original) + sizeof(WAVEFORMATEX)), 1, cbExtra );
445                                 }
446                         }
447                         else {
448                                 Int3();         // malloc failed
449                                 goto OPEN_ERROR;
450                         }       
451                         break;
452
453                 case 0x61746164:                // the 'data' tag
454                         m_nDataSize = size;     // This is size of data chunk.  Compressed if ADPCM.
455                         m_data_bytes_left = size;
456                         m_data_offset = SDL_RWtell( cfp );
457                         done = TRUE;
458                         break;
459
460                 default:        // unknown, skip it
461                         break;
462                 }       // end switch
463
464                 SDL_RWseek( cfp, next_chunk, SEEK_SET );
465         }
466
467         // At this stage, examine source format, and set up WAVEFORATEX structure for DirectSound.
468         // Since DirectSound only supports PCM, force this structure to be PCM compliant.  We will
469         // need to convert data on the fly later if our souce is not PCM
470         switch ( m_pwfmt_original->wFormatTag ) {
471                 case WAVE_FORMAT_PCM:
472                         m_wave_format = WAVE_FORMAT_PCM;
473                         m_wfmt.wBitsPerSample = m_pwfmt_original->wBitsPerSample;
474                         break;
475
476                 case WAVE_FORMAT_ADPCM:
477                         m_wave_format = WAVE_FORMAT_ADPCM;
478                         m_wfmt.wBitsPerSample = 16;
479                         m_bits_per_sample_uncompressed = 16;
480                         break;
481
482                 default:
483                         nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n", m_pwfmt_original->wFormatTag));
484                         //Int3();
485                         goto OPEN_ERROR;
486                         break;
487
488         } // end switch
489             
490         // Set up the WAVEFORMATEX structure to have the right PCM characteristics
491         m_wfmt.wFormatTag = WAVE_FORMAT_PCM;
492         m_wfmt.nChannels = m_pwfmt_original->nChannels;
493         m_wfmt.nSamplesPerSec = m_pwfmt_original->nSamplesPerSec;
494         m_wfmt.cbSize = 0;
495         m_wfmt.nBlockAlign = (ushort)(( m_wfmt.nChannels * m_wfmt.wBitsPerSample ) / 8);
496         m_wfmt.nAvgBytesPerSec = m_wfmt.nBlockAlign * m_wfmt.nSamplesPerSec;
497
498         // Init some member data from format chunk
499         m_nBlockAlign = m_pwfmt_original->nBlockAlign;
500         m_nUncompressedAvgDataRate = m_wfmt.nAvgBytesPerSec;
501
502         // Cue for streaming
503         Cue ();
504
505         // Successful open
506         goto OPEN_DONE;
507     
508 OPEN_ERROR:
509         // Handle all errors here
510         nprintf(("SOUND","SOUND ==> Could not open wave file %s for streaming\n",pszFilename));
511
512         fRtn = FAILURE;
513         if (cfp != NULL) {
514                 // Close file
515                 SDL_RWclose( cfp );
516                 cfp = NULL;
517         }
518         if (m_pwfmt_original)
519         {
520                 free(m_pwfmt_original);
521                 m_pwfmt_original = NULL;
522         }
523
524 OPEN_DONE:
525         return (fRtn);
526 }
527
528 // Cue
529 //
530 // Set the file pointer to the start of wave data
531 //
532 BOOL WaveFile::Cue (void)
533 {
534         BOOL fRtn = SUCCESS;    // assume success
535         int rval = -1;
536
537         m_total_uncompressed_bytes_read = 0;
538         m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
539
540         rval = SDL_RWseek( cfp, m_data_offset, SEEK_SET );
541
542         if ( rval == -1 ) {
543                 fRtn = FAILURE;
544         }
545
546         m_data_bytes_left = m_nDataSize;
547         m_abort_next_read = FALSE;
548
549         return fRtn;
550 }
551
552
553 // Read
554 //
555 // Returns number of bytes actually read.
556 // 
557 //      Returns -1 if there is nothing more to be read.  This function can return 0, since
558 // sometimes the amount of bytes requested is too small for the ACM decompression to 
559 // locate a suitable block
560 int WaveFile::Read(ubyte *pbDest, uint cbSize, int service)
561 {
562         void    *dest_buf=NULL, *uncompressed_wave_data;
563         int                             rc, uncompressed_bytes_written;
564         uint    src_bytes_used, convert_len, num_bytes_desired=0, num_bytes_read;
565
566 //      nprintf(("Alan","Reqeusted: %d\n", cbSize));
567
568         if ( service ) {
569                 uncompressed_wave_data = Wavedata_service_buffer;
570         } else {
571                 uncompressed_wave_data = Wavedata_load_buffer;
572         }
573
574         switch ( m_wave_format ) {
575                 case WAVE_FORMAT_PCM:
576                         num_bytes_desired = cbSize;
577                         dest_buf = pbDest;
578                         break;
579
580                 case WAVE_FORMAT_ADPCM:
581                         if ( !m_hStream_open ) {
582                                 if ( !ACM_stream_open(m_pwfmt_original, &m_wfxDest, (void**)&m_hStream, m_bits_per_sample_uncompressed)  ) {
583                                         m_hStream_open = 1;
584                                 } else {
585                                         Int3();
586                                 }
587                         }
588
589                         num_bytes_desired = cbSize;
590         
591                         if ( service ) {
592                                 dest_buf = Compressed_service_buffer;
593                         } else {
594                                 dest_buf = Compressed_buffer;
595                         }
596
597                         if ( num_bytes_desired <= 0 ) {
598                                 num_bytes_desired = 0;
599 //                              nprintf(("Alan","No bytes required for ADPCM time interval\n"));
600                         } else {
601                                 num_bytes_desired = ACM_query_source_size((void*)m_hStream, cbSize);
602 //                              nprintf(("Alan","Num bytes desired: %d\n", num_bytes_desired));
603                         }
604                         break;
605
606                 default:
607                         nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n"));
608                         Int3();
609                         break;
610
611         } // end switch
612
613         num_bytes_read = 0;
614         convert_len = 0;
615         src_bytes_used = 0;
616
617         // read data from disk
618         if ( m_data_bytes_left <= 0 ) {
619                 num_bytes_read = 0;
620                 uncompressed_bytes_written = 0;
621                 return -1;
622         }
623
624         if ( (m_data_bytes_left > 0) && (num_bytes_desired > 0) ) {
625                 int actual_read = 0;
626
627                 if ( num_bytes_desired <= (uint)m_data_bytes_left ) {
628                         num_bytes_read = num_bytes_desired;
629                 }
630                 else {
631                         num_bytes_read = m_data_bytes_left;
632                 }
633
634                 actual_read = SDL_RWread( cfp, dest_buf, 1, num_bytes_read );
635
636                 if ( (actual_read <= 0) || (m_abort_next_read) ) {
637                         num_bytes_read = 0;
638                         uncompressed_bytes_written = 0;
639                         return -1;
640                 }
641
642                 if ( num_bytes_desired >= (uint)m_data_bytes_left ) {
643                         m_abort_next_read = 1;                  
644                 }
645
646                 num_bytes_read = actual_read;
647         }
648
649         // convert data if necessary, to PCM
650         if ( m_wave_format == WAVE_FORMAT_ADPCM ) {
651                 if ( num_bytes_read > 0 ) {
652                         rc = ACM_convert((void*)m_hStream, (ubyte*)dest_buf, num_bytes_read, (ubyte*)uncompressed_wave_data, BIGBUF_SIZE, &convert_len, &src_bytes_used);
653
654                         if ( rc == -1 ) {
655                                 goto READ_ERROR;
656                         }
657                         if ( convert_len == 0 ) {
658                                 Int3();
659                         }
660                 }
661
662                 Assert(src_bytes_used <= num_bytes_read);
663                 if ( src_bytes_used < num_bytes_read ) {
664                         // seek back file pointer to reposition before unused source data
665                         SDL_RWseek( cfp, src_bytes_used - num_bytes_read, SEEK_CUR );
666                 }
667
668                 // Adjust number of bytes left
669                 m_data_bytes_left -= src_bytes_used;
670                 m_nBytesPlayed += src_bytes_used;
671                 uncompressed_bytes_written = convert_len;
672
673                 // Successful read, keep running total of number of data bytes read
674                 goto READ_DONE;
675         }
676         else {
677                 // Successful read, keep running total of number of data bytes read
678                 // Adjust number of bytes left
679                 m_data_bytes_left -= num_bytes_read;
680                 m_nBytesPlayed += num_bytes_read;
681                 uncompressed_bytes_written = num_bytes_read;
682                 goto READ_DONE;
683         }
684     
685 READ_ERROR:
686         num_bytes_read = 0;
687         uncompressed_bytes_written = 0;
688
689 READ_DONE:
690         m_total_uncompressed_bytes_read += uncompressed_bytes_written;
691 //      nprintf(("Alan","Read: %d\n", uncompressed_bytes_written));
692         return (uncompressed_bytes_written);
693 }
694
695
696 // GetSilenceData
697 //
698 // Returns 8 bits of data representing silence for the Wave file format.
699 //
700 // Since we are dealing only with PCM format, we can fudge a bit and take
701 // advantage of the fact that for all PCM formats, silence can be represented
702 // by a single byte, repeated to make up the proper word size. The actual size
703 // of a word of wave data depends on the format:
704 //
705 // PCM Format       Word Size       Silence Data
706 // 8-bit mono       1 byte          0x80
707 // 8-bit stereo     2 bytes         0x8080
708 // 16-bit mono      2 bytes         0x0000
709 // 16-bit stereo    4 bytes         0x00000000
710 //
711 ubyte WaveFile::GetSilenceData (void)
712 {
713         ubyte bSilenceData = 0;
714
715         // Silence data depends on format of Wave file
716         if (m_pwfmt_original) {
717                 if (m_wfmt.wBitsPerSample == 8) {
718                         // For 8-bit formats (unsigned, 0 to 255)
719                         // Packed DWORD = 0x80808080;
720                         bSilenceData = 0x80;
721                 } else if (m_wfmt.wBitsPerSample == 16) {
722                         // For 16-bit formats (signed, -32768 to 32767)
723                         // Packed DWORD = 0x00000000;
724                         bSilenceData = 0x00;
725                 } else {
726                         Int3();
727                 }
728         } else {
729                 Int3();
730         }
731
732         return (bSilenceData);
733 }
734
735 //
736 // AudioStream class implementation
737 //
738 ////////////////////////////////////////////////////////////
739
740 // The following constants are the defaults for our streaming buffer operation.
741 const ushort DefBufferLength          = 2000; // default buffer length in msec
742 const ushort DefBufferServiceInterval = 250;  // default buffer service interval in msec
743
744 // Constructor
745 AudioStream::AudioStream (void)
746 {
747         SDL_LockMutex(write_lock);
748 }
749
750 // Destructor
751 AudioStream::~AudioStream (void)
752 {
753         SDL_UnlockMutex(write_lock);
754 }
755
756 void AudioStream::Init_Data ()
757 {
758         m_bLooping = 0;
759         m_bFade = FALSE;
760         m_fade_timer_id = 0;
761         m_finished_id = 0;
762         m_bPastLimit = FALSE;
763         
764         m_bDestroy_when_faded = FALSE;
765         m_lVolume = 0;
766         m_lCutoffVolume = -10000;
767         m_bIsPaused = FALSE;
768         m_silence_written = 0;
769         m_bReadingDone = FALSE;
770
771         m_pwavefile = NULL;
772         m_fPlaying = m_fCued = FALSE;
773         m_lInService = FALSE;
774         m_cbBufOffset = 0;
775         m_nBufLength = DefBufferLength;
776         m_cbBufSize = 0;
777         m_nBufService = DefBufferServiceInterval;
778         m_nTimeStarted = 0;
779
780         memset(m_buffer_ids, 0, sizeof(m_buffer_ids));
781         m_source_id = 0;
782         m_play_buffer_id = 0;
783 }
784
785 // Create
786 BOOL AudioStream::Create (char *pszFilename)
787 {
788
789         BOOL fRtn = SUCCESS;    // assume success
790
791         Assert(pszFilename);
792
793         Init_Data();
794
795         if (pszFilename) {
796                 // make 100% sure we got a good filename
797                 if ( !strlen(pszFilename) )
798                         return FAILURE;
799
800                 // Create a new WaveFile object
801                 m_pwavefile = (WaveFile *)malloc(sizeof(WaveFile));
802                 Assert(m_pwavefile);
803
804                 if (m_pwavefile) {
805                         // Call constructor
806                         m_pwavefile->Init();
807                         // Open given file
808                         m_pwavefile->m_bits_per_sample_uncompressed = m_bits_per_sample_uncompressed;
809                         if (m_pwavefile->Open (pszFilename)) {
810                                 // Calculate sound buffer size in bytes
811                                 // Buffer size is average data rate times length of buffer
812                                 // No need for buffer to be larger than wave data though
813                                 m_cbBufSize = (m_nBufLength/1000) * (m_pwavefile->m_wfmt.wBitsPerSample/8) * m_pwavefile->m_wfmt.nChannels * m_pwavefile->m_wfmt.nSamplesPerSec;
814                                 m_cbBufSize /= MAX_STREAM_BUFFERS;
815                                 // if the requested buffer size is too big then cap it
816                                 m_cbBufSize = (m_cbBufSize > BIGBUF_SIZE) ? BIGBUF_SIZE : m_cbBufSize; 
817
818 //                              nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
819
820                                 // Create sound buffer
821                                 OpenAL_ErrorCheck( alGenBuffers(MAX_STREAM_BUFFERS, m_buffer_ids), return FAILURE );
822                                 
823                                 OpenAL_ErrorCheck( alGenSources(1, &m_source_id), return FAILURE );
824                                 
825                                 OpenAL_ErrorPrint( alSourcef(m_source_id, AL_ROLLOFF_FACTOR, 0) );
826
827                                 OpenAL_ErrorPrint( alSourcei(m_source_id, AL_SOURCE_RELATIVE, AL_TRUE) );
828
829                                 ALfloat posv[] = { 0, 0, 0 };
830                                 OpenAL_ErrorPrint( alSourcefv(m_source_id, AL_POSITION, posv) );
831
832                                 OpenAL_ErrorPrint( alSourcef(m_source_id, AL_GAIN, 1) );
833
834                                 // Cue for playback
835                                 Cue();
836                                 Snd_sram += m_cbBufSize;
837                         }
838                         else {
839                                 // Error opening file
840                                 nprintf(("SOUND", "SOUND => Failed to open wave file: %s\n\r", pszFilename));
841                                 m_pwavefile->Close();
842                                 free(m_pwavefile);
843                                 m_pwavefile = NULL;
844                                 fRtn = FAILURE;
845                         }   
846                 }
847                 else {
848                         // Error, unable to create WaveFile object
849                         nprintf(("Sound", "SOUND => Failed to create WaveFile object %s\n\r", pszFilename));
850                         fRtn = FAILURE;
851                 }
852         }
853         else {
854                 // Error, passed invalid parms
855                 fRtn = FAILURE;
856         }
857
858         return (fRtn);
859 }
860
861 // Destroy
862 BOOL AudioStream::Destroy (void)
863 {
864         BOOL fRtn = SUCCESS;
865
866         SDL_LockMutex(write_lock);
867
868         // Stop playback
869         Stop ();
870
871         // Release sound buffer
872         OpenAL_ErrorPrint( alDeleteBuffers(MAX_STREAM_BUFFERS, m_buffer_ids) );
873         OpenAL_ErrorPrint( alDeleteSources(1, &m_source_id) );
874         Snd_sram -= m_cbBufSize;
875
876         // Delete WaveFile object
877         if (m_pwavefile) {
878                 m_pwavefile->Close();
879                 free(m_pwavefile);
880                 m_pwavefile = NULL;
881         }
882
883         status = ASF_FREE;
884
885         SDL_UnlockMutex(write_lock);
886
887         return fRtn;
888 }
889
890 // WriteWaveData
891 //
892 // Writes wave data to sound buffer. This is a helper method used by Create and
893 // ServiceBuffer; it's not exposed to users of the AudioStream class.
894 BOOL AudioStream::WriteWaveData (uint size, uint *num_bytes_written, int service)
895 {
896         BOOL fRtn = SUCCESS;
897         ubyte *uncompressed_wave_data;
898
899         *num_bytes_written = 0;
900
901         if ( size == 0 || m_bReadingDone ) {
902                 return fRtn;
903         }
904
905         if ( (m_buffer_ids[0] == 0) || !m_pwavefile ) {
906                 return fRtn;
907         }
908
909         if ( service ) {
910                 SDL_LockMutex(Global_service_lock);
911         }
912                     
913         if ( service ) {
914                 uncompressed_wave_data = Wavedata_service_buffer;
915         } else {
916                 uncompressed_wave_data = Wavedata_load_buffer;
917         }
918
919         int num_bytes_read = 0;
920
921         // Lock the sound buffer
922         num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize, service);
923
924         if ( num_bytes_read == -1 ) {
925                 // means nothing left to read!
926                 num_bytes_read = 0;
927                 m_bReadingDone = 1;
928         }
929
930         if ( num_bytes_read > 0 ) {
931         //      nprintf(("SOUND", "SOUND ==> Queueing %d bytes of Data\n", num_bytes_read));
932
933                 // Lock the sound buffer
934                 ALenum format = AL_FORMAT_MONO8;
935
936                 if (m_pwavefile->m_wfmt.nChannels == 1) {
937                         if (m_pwavefile->m_wfmt.wBitsPerSample == 8) 
938                                 format = AL_FORMAT_MONO8;
939                         else if (m_pwavefile->m_wfmt.wBitsPerSample == 16) 
940                                 format = AL_FORMAT_MONO16;
941                 } else if (m_pwavefile->m_wfmt.nChannels == 2) {
942                         if (m_pwavefile->m_wfmt.wBitsPerSample == 8) 
943                                 format = AL_FORMAT_STEREO8;
944                         else if (m_pwavefile->m_wfmt.wBitsPerSample == 16) 
945                                 format = AL_FORMAT_STEREO16;
946                 }
947
948                 // unqueue and recycle a processed buffer
949                 ALint p = 0;
950                 ALuint bid;
951
952                 OpenAL_ErrorPrint( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &p) );
953
954                 if ( p > 0 ) {
955                         OpenAL_ErrorPrint( alSourceUnqueueBuffers(m_source_id, 1, &bid) );
956                 }
957
958                 OpenAL_ErrorCheck( alBufferData(m_buffer_ids[m_play_buffer_id], format, uncompressed_wave_data, num_bytes_read, m_pwavefile->m_wfmt.nSamplesPerSec), return FAILURE );
959
960                 OpenAL_ErrorCheck( alSourceQueueBuffers(m_source_id, 1, &m_buffer_ids[m_play_buffer_id]), return FAILURE );
961
962                 m_play_buffer_id++;
963
964                 if (m_play_buffer_id >= MAX_STREAM_BUFFERS)
965                         m_play_buffer_id = 0;
966         }
967
968         if ( service ) {
969                 SDL_UnlockMutex(Global_service_lock);
970         }
971     
972         return (fRtn);
973 }
974
975
976 // WriteSilence
977 //
978 // Writes silence to sound buffer. This is a helper method used by
979 // ServiceBuffer; it's not exposed to users of the AudioStream class.
980 BOOL AudioStream::WriteSilence (uint size)
981 {
982         BOOL fRtn = SUCCESS;
983
984         // not used currently with the OpenAL code
985
986         return (fRtn);
987 }
988
989
990 // GetMaxWriteSize
991 //
992 // Helper function to calculate max size of sound buffer write operation, i.e. how much
993 // free space there is in buffer.
994 DWORD AudioStream::GetMaxWriteSize (void)
995 {
996         DWORD dwMaxSize = m_cbBufSize;
997         ALint n, q;
998
999         OpenAL_ErrorCheck( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &n), return 0 );
1000
1001         OpenAL_ErrorCheck( alGetSourcei(m_source_id, AL_BUFFERS_QUEUED, &q), return 0 );
1002
1003         if (!n && (q >= MAX_STREAM_BUFFERS)) //all buffers queued
1004                 dwMaxSize = 0;
1005
1006         //      nprintf(("Alan","Max write size: %d\n", dwMaxSize));
1007         return (dwMaxSize);
1008 }
1009
1010 #define FADE_VOLUME_INTERVAL                                                    400             // 100 == 1db
1011 #define VOLUME_ATTENUATION_BEFORE_CUTOFF                        3000            //  12db 
1012 BOOL AudioStream::ServiceBuffer (void)
1013 {
1014         long    vol;
1015         int     fRtn = TRUE;
1016
1017         if ( status != ASF_USED )
1018                 return FALSE;
1019
1020         SDL_LockMutex(write_lock);
1021
1022         // status may have changed, so lets check once again
1023         if ( status != ASF_USED ){
1024                 SDL_UnlockMutex(write_lock);
1025
1026                 return FALSE;
1027         }
1028
1029         if ( m_bFade == TRUE ) {
1030                 if ( m_lCutoffVolume == -10000 ) {
1031                         vol = Get_Volume();
1032 //                      nprintf(("Alan","Volume is: %d\n",vol));
1033                         m_lCutoffVolume = max(vol - VOLUME_ATTENUATION_BEFORE_CUTOFF, -10000);
1034                 }
1035
1036                 vol = Get_Volume();
1037                 vol = vol - FADE_VOLUME_INTERVAL;       // decrease by 1db
1038 //              nprintf(("Alan","Volume is now: %d\n",vol));
1039                 Set_Volume(vol);
1040
1041 //              nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
1042 //              nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
1043                 if ( vol < m_lCutoffVolume ) {
1044                         m_bFade = 0;
1045                         m_lCutoffVolume = -10000;
1046                         if ( m_bDestroy_when_faded == TRUE ) {
1047                                 SDL_UnlockMutex(write_lock);
1048
1049                                 Destroy();      
1050                                 // Reset reentrancy semaphore
1051
1052                                 return FALSE;
1053                         }
1054                         else {
1055                                 Stop_and_Rewind();
1056                                 // Reset reentrancy semaphore
1057                                 SDL_UnlockMutex(write_lock);
1058
1059                                 return TRUE;
1060                         }
1061                 }
1062         }
1063
1064         // All of sound not played yet, send more data to buffer
1065         DWORD dwFreeSpace = GetMaxWriteSize ();
1066
1067         // Determine free space in sound buffer
1068         if (dwFreeSpace) {
1069
1070                 // Some wave data remains, but not enough to fill free space
1071                 // Send wave data to buffer, fill remainder of free space with silence
1072                 uint num_bytes_written;
1073
1074                 if (WriteWaveData (dwFreeSpace, &num_bytes_written) == SUCCESS) {
1075 //                      nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));
1076
1077                         if ( m_pwavefile->m_total_uncompressed_bytes_read >= m_pwavefile->m_max_uncompressed_bytes_to_read ) {
1078                                 m_fade_timer_id = timer_get_milliseconds() + 1700;              // start fading 1.7 seconds from now
1079                                 m_finished_id = timer_get_milliseconds() + 2000;                // 2 seconds left to play out buffer
1080                                 m_pwavefile->m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1081                         }
1082
1083                         if ( (m_fade_timer_id>0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
1084                                 m_fade_timer_id = 0;
1085                                 Fade_and_Stop();
1086                         }
1087
1088                         if ( (m_finished_id>0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
1089                                 m_finished_id = 0;
1090                                 m_bPastLimit = TRUE;
1091                         }
1092
1093                         ALint n = 0;
1094                         // get the number of buffers processed to see if we're done
1095                         OpenAL_ErrorCheck( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &n), return FALSE );
1096
1097                         if ( m_bReadingDone && (n == MAX_STREAM_BUFFERS) ) {
1098                                 if ( m_bDestroy_when_faded == TRUE ) {
1099                                         SDL_UnlockMutex(write_lock);
1100
1101                                         Destroy();
1102                                         // Reset reentrancy semaphore
1103
1104                                         return FALSE;
1105                                 }
1106                                 // All of sound has played, stop playback or loop again
1107                                 if ( m_bLooping && !m_bFade) {
1108                                         Play(m_lVolume, m_bLooping);
1109                                 }
1110                                 else {
1111                                         Stop_and_Rewind();
1112                                 }
1113                         }
1114                 }
1115                 else {
1116                         // Error writing wave data
1117                         fRtn = FALSE;
1118                         Int3(); 
1119                 }
1120         }
1121
1122
1123         SDL_UnlockMutex(write_lock);
1124
1125         return (fRtn);
1126 }
1127
1128 // Cue
1129 void AudioStream::Cue (void)
1130 {
1131         uint num_bytes_written;
1132
1133         if (!m_fCued) {
1134                 m_bFade = FALSE;
1135                 m_fade_timer_id = 0;
1136                 m_finished_id = 0;
1137                 m_bPastLimit = FALSE;
1138                 m_lVolume = 0;
1139                 m_lCutoffVolume = -10000;
1140
1141                 m_bDestroy_when_faded = FALSE;
1142
1143                 // Reset buffer ptr
1144                 m_cbBufOffset = 0;
1145
1146                 // Reset file ptr, etc
1147                 m_pwavefile->Cue ();
1148
1149                 // Unqueue all buffers
1150                 ALint p = 0;
1151                 OpenAL_ErrorPrint( alGetSourcei(m_source_id, AL_BUFFERS_PROCESSED, &p) );
1152                 OpenAL_ErrorPrint( alSourceUnqueueBuffers(m_source_id, p, m_buffer_ids) );
1153
1154                 // Fill buffer with wave data
1155                 WriteWaveData (m_cbBufSize, &num_bytes_written, 0);
1156
1157                 m_fCued = TRUE;
1158         }
1159 }
1160
1161 // Play
1162 void AudioStream::Play (long volume, int looping)
1163 {
1164         if (m_buffer_ids[0] != 0) {
1165                 // If playing, stop
1166                 if (m_fPlaying) {
1167                         if ( m_bIsPaused == FALSE)
1168                                 Stop_and_Rewind();
1169                 }
1170
1171                 // Cue for playback if necessary
1172                 if (!m_fCued) {
1173                         Cue ();
1174                 }
1175
1176                 if ( looping )
1177                         m_bLooping = 1;
1178                 else
1179                         m_bLooping = 0;
1180
1181                 OpenAL_ErrorPrint( alSourcePlay(m_source_id) );
1182
1183                 m_nTimeStarted = timer_get_milliseconds();
1184                 Set_Volume(volume);
1185
1186                 // Kick off timer to service buffer
1187                 m_timer.constructor();
1188
1189                 m_timer.Create (m_nBufService, m_nBufService, ptr_u (this), TimerCallback);
1190
1191                 // Playback begun, no longer cued
1192                 m_fPlaying = TRUE;
1193                 m_bIsPaused = FALSE;
1194         }
1195 }
1196
1197 // Timer callback for Timer object created by ::Play method.
1198 BOOL AudioStream::TimerCallback (ptr_u dwUser)
1199 {
1200     // dwUser contains ptr to AudioStream object
1201     AudioStream * pas = (AudioStream *) dwUser;
1202
1203     return (pas->ServiceBuffer ());
1204 }
1205
1206 void AudioStream::Set_Byte_Cutoff(unsigned int byte_cutoff)
1207 {
1208         if ( m_pwavefile == NULL )
1209                 return;
1210
1211         m_pwavefile->m_max_uncompressed_bytes_to_read = byte_cutoff;
1212 }
1213
1214 unsigned int AudioStream::Get_Bytes_Committed(void)
1215 {
1216         if ( m_pwavefile == NULL )
1217                 return 0;
1218
1219         return m_pwavefile->m_total_uncompressed_bytes_read;
1220 }
1221
1222
1223 // Fade_and_Destroy
1224 void AudioStream::Fade_and_Destroy (void)
1225 {
1226         m_bFade = TRUE;
1227         m_bDestroy_when_faded = TRUE;
1228 }
1229
1230 // Fade_and_Destroy
1231 void AudioStream::Fade_and_Stop (void)
1232 {
1233         m_bFade = TRUE;
1234         m_bDestroy_when_faded = FALSE;
1235 }
1236
1237
1238 // Stop
1239 void AudioStream::Stop(int paused)
1240 {
1241         if (m_fPlaying) {
1242                 if (paused) {
1243                         OpenAL_ErrorPrint( alSourcePause(m_source_id) );
1244                 } else {
1245                         OpenAL_ErrorPrint( alSourceStop(m_source_id) );
1246                 }
1247
1248                 m_fPlaying = FALSE;
1249                 m_bIsPaused = paused;
1250
1251                 // Delete Timer object
1252                 m_timer.destructor();
1253         }
1254 }
1255
1256 // Stop_and_Rewind
1257 void AudioStream::Stop_and_Rewind (void)
1258 {
1259         if (m_fPlaying) {
1260                 // Stop playback
1261                 OpenAL_ErrorPrint( alSourceStop(m_source_id) );
1262
1263                 // Delete Timer object
1264                 m_timer.destructor();
1265
1266                 m_fPlaying = FALSE;
1267         }
1268
1269         m_fCued = FALSE;        // this will cause wave file to start from beginning
1270         m_bReadingDone = FALSE;
1271 }
1272
1273 // Set_Volume
1274 void AudioStream::Set_Volume(long vol)
1275 {
1276         if ( vol < -10000 )
1277                 vol = -10000;
1278         
1279         if ( vol > 0 )
1280                 vol = 0;
1281
1282         Assert( vol >= -10000 && vol <= 0 );
1283
1284         ALfloat alvol = (vol != -10000) ? powf(10.0f, (float)vol / (-600.0f / log10f(.5f))): 0.0f;
1285
1286         OpenAL_ErrorPrint( alSourcef(m_source_id, AL_GAIN, alvol) );
1287
1288         m_lVolume = vol;
1289         if ( h_result != 0 )
1290                 nprintf(("Sound","SOUND => SetVolume() failed with code '%s'\n", get_DSERR_text(h_result) ));
1291 }
1292
1293
1294 // Set_Volume
1295 long AudioStream::Get_Volume()
1296 {
1297         return m_lVolume;
1298 }
1299
1300
1301
1302 AudioStream Audio_streams[MAX_AUDIO_STREAMS];
1303
1304
1305 void audiostream_init()
1306 {
1307         int i;
1308
1309         if ( Audiostream_inited == 1 )
1310                 return;
1311
1312         if ( !ACM_is_inited() ) {
1313                 return;
1314         }
1315
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);
1320                 Assert(Wavedata_load_buffer != NULL);
1321         }
1322
1323         // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
1324         // disk during a service interval
1325         if ( Wavedata_service_buffer == NULL ) {
1326                 Wavedata_service_buffer = (ubyte*)malloc(BIGBUF_SIZE);
1327                 Assert(Wavedata_service_buffer != NULL);
1328         }
1329
1330         // Allocate memory for the buffer which holds the compressed wave data that is read from the hard disk
1331         if ( Compressed_buffer == NULL ) {
1332                 Compressed_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1333                 Assert(Compressed_buffer != NULL);
1334         }
1335
1336         if ( Compressed_service_buffer == NULL ) {
1337                 Compressed_service_buffer = (ubyte*)malloc(COMPRESSED_BUFFER_SIZE);
1338                 Assert(Compressed_service_buffer != NULL);
1339         }
1340
1341         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1342                 Audio_streams[i].Init_Data();
1343                 Audio_streams[i].status = ASF_FREE;
1344                 Audio_streams[i].type = ASF_NONE;
1345         }
1346
1347         SDL_InitSubSystem(SDL_INIT_TIMER);
1348
1349         Global_service_lock = SDL_CreateMutex();
1350
1351         Audiostream_inited = 1;
1352 }
1353
1354 // Close down the audiostream system.  Must call audiostream_init() before any audiostream functions can
1355 // be used.
1356 void audiostream_close()
1357 {
1358         if ( Audiostream_inited == 0 )
1359                 return;
1360
1361         int i;
1362
1363         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1364                 if ( Audio_streams[i].status == ASF_USED ) {
1365                         Audio_streams[i].status = ASF_FREE;
1366                         Audio_streams[i].Destroy();
1367                 }
1368         }
1369
1370         // free global buffers
1371         if ( Wavedata_load_buffer ) {
1372                 free(Wavedata_load_buffer);
1373                 Wavedata_load_buffer = NULL;
1374         }
1375
1376         if ( Wavedata_service_buffer ) {
1377                 free(Wavedata_service_buffer);
1378                 Wavedata_service_buffer = NULL;
1379         }
1380
1381         if ( Compressed_buffer ) {
1382                 free(Compressed_buffer);
1383                 Compressed_buffer = NULL;
1384         }
1385
1386         if ( Compressed_service_buffer ) {
1387                 free(Compressed_service_buffer);
1388                 Compressed_service_buffer = NULL;
1389         }
1390
1391         SDL_DestroyMutex( Global_service_lock );
1392
1393         Audiostream_inited = 0;
1394
1395 }
1396
1397 // Open a digital sound file for streaming
1398 //
1399 // input:       filename        =>      disk filename of sound file
1400 //                              type            => what type of audio stream do we want to open:
1401 //                                                                      ASF_SOUNDFX
1402 //                                                                      ASF_EVENTMUSIC
1403 //                                                                      ASF_VOICE
1404 //      
1405 // returns:     success => handle to identify streaming sound
1406 //                              failure => -1
1407 int audiostream_open( char *filename, int type )
1408 {
1409         int i, rc;
1410
1411         if (!Audiostream_inited || !snd_is_inited())
1412                 return -1;
1413
1414         for ( i=0; i<MAX_AUDIO_STREAMS; i++ ) {
1415                 if ( Audio_streams[i].status == ASF_FREE ) {
1416                         Audio_streams[i].status = ASF_USED;
1417                         Audio_streams[i].type = type;
1418                         break;
1419                 }
1420         }
1421
1422         if ( i == MAX_AUDIO_STREAMS ) {
1423                 nprintf(("Sound", "SOUND => No more audio streams available!\n"));
1424                 return -1;
1425         }
1426
1427         switch(type) {
1428                 case ASF_VOICE:
1429                 case ASF_SOUNDFX:
1430                         Audio_streams[i].m_bits_per_sample_uncompressed = 8;
1431                 case ASF_EVENTMUSIC:
1432                         Audio_streams[i].m_bits_per_sample_uncompressed = 16;
1433                         break;
1434                 default:
1435                         Int3();
1436                         return -1;
1437         }
1438
1439         rc = Audio_streams[i].Create(filename);
1440
1441         if ( rc == 0 ) {
1442                 Audio_streams[i].status = ASF_FREE;
1443                 return -1;
1444         } else {
1445                 return i;
1446         }
1447 }
1448
1449 void audiostream_close_file(int i, int fade)
1450 {
1451         if (!Audiostream_inited)
1452                 return;
1453
1454         if ( i == -1 )
1455                 return;
1456
1457         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1458
1459         if ( Audio_streams[i].status == ASF_USED ) {
1460                 if ( fade == TRUE ) {
1461                         Audio_streams[i].Fade_and_Destroy();
1462                 } else {
1463                         Audio_streams[i].Destroy();
1464                 }
1465         }
1466
1467 }
1468
1469 void audiostream_close_all(int fade)
1470 {
1471         int i;
1472
1473         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1474                 if ( Audio_streams[i].status == ASF_FREE )
1475                         continue;
1476
1477                 audiostream_close_file(i, fade);
1478         }
1479 }
1480
1481 void audiostream_play(int i, float volume, int looping)
1482 {
1483         if (!Audiostream_inited)
1484                 return;
1485
1486         if ( i == -1 )
1487                 return;
1488
1489         Assert(looping >= 0);
1490         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1491
1492         // convert from 0->1 to -10000->0 for volume
1493         int converted_volume;
1494         if ( volume == -1 ) {
1495                 converted_volume = Audio_streams[i].Get_Default_Volume();
1496         }
1497         else {
1498                 Assert(volume >= 0.0f && volume <= 1.0f );
1499                 converted_volume = ds_convert_volume(volume);
1500         }
1501
1502         Assert( Audio_streams[i].status == ASF_USED );
1503         Audio_streams[i].Set_Default_Volume(converted_volume);
1504         Audio_streams[i].Play(converted_volume, looping);
1505 }
1506
1507 // use as buffer service function
1508 int audiostream_is_playing(int i)
1509 {
1510         if ( i == -1 )
1511                 return 0;
1512
1513         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1514         if ( Audio_streams[i].status != ASF_USED )
1515                 return 0;
1516
1517         return Audio_streams[i].Is_Playing();
1518 }
1519
1520 void audiostream_stop(int i, int rewind, int paused)
1521 {
1522         if (!Audiostream_inited)
1523                 return;
1524
1525         if ( i == -1 )
1526                 return;
1527
1528         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1529         Assert( Audio_streams[i].status == ASF_USED );
1530
1531         if ( rewind )
1532                 Audio_streams[i].Stop_and_Rewind();
1533         else
1534                 Audio_streams[i].Stop(paused);
1535 }
1536
1537 void audiostream_set_volume_all(float volume, int type)
1538 {
1539         int i;
1540
1541         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1542                 if ( Audio_streams[i].status == ASF_FREE )
1543                         continue;
1544
1545                 if ( Audio_streams[i].type == type ) {
1546                         int converted_volume;
1547                         converted_volume = ds_convert_volume(volume);
1548                         Audio_streams[i].Set_Volume(converted_volume);
1549                 }
1550         }
1551 }
1552
1553 void audiostream_set_volume(int i, float volume)
1554 {
1555         if ( i == -1 )
1556                 return;
1557
1558         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1559         Assert( volume >= 0 && volume <= 1);
1560
1561         if ( Audio_streams[i].status == ASF_FREE )
1562                 return;
1563
1564         int converted_volume;
1565         converted_volume = ds_convert_volume(volume);
1566         Audio_streams[i].Set_Volume(converted_volume);
1567 }
1568
1569 int audiostream_is_paused(int i)
1570 {
1571         if ( i == -1 )
1572                 return 0;
1573
1574         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1575         if ( Audio_streams[i].status == ASF_FREE )
1576                 return -1;
1577
1578         BOOL is_paused;
1579         is_paused = Audio_streams[i].Is_Paused();
1580
1581         return is_paused;
1582 }
1583
1584 void audiostream_set_byte_cutoff(int i, unsigned int cutoff)
1585 {
1586         if ( i == -1 )
1587                 return;
1588
1589         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1590         Assert( cutoff > 0 );
1591
1592         if ( Audio_streams[i].status == ASF_FREE )
1593                 return;
1594
1595         Audio_streams[i].Set_Byte_Cutoff(cutoff);
1596 }
1597
1598 uint audiostream_get_bytes_committed(int i)
1599 {
1600         if ( i == -1 )
1601                 return 0;
1602
1603         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1604
1605         if ( Audio_streams[i].status == ASF_FREE )
1606                 return 0;
1607
1608         uint num_bytes_committed;
1609         num_bytes_committed = Audio_streams[i].Get_Bytes_Committed();
1610         
1611         return num_bytes_committed;
1612 }
1613
1614 int audiostream_done_reading(int i)
1615 {
1616         if ( i == -1 )
1617                 return 0;
1618
1619         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1620
1621         if ( Audio_streams[i].status == ASF_FREE )
1622                 return 0;
1623
1624         int done_reading;
1625         done_reading = Audio_streams[i].Is_Past_Limit();
1626         
1627         return done_reading;
1628 }
1629
1630 int audiostream_is_inited()
1631 {
1632         return Audiostream_inited;
1633 }
1634
1635 void audiostream_pause(int i)
1636 {
1637         if ( i == -1 )
1638                 return;
1639
1640         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1641         if ( Audio_streams[i].status == ASF_FREE )
1642                 return;
1643
1644         if ( audiostream_is_playing(i) == TRUE ) {
1645                 audiostream_stop(i, 0, 1);
1646         }
1647 }
1648
1649 void audiostream_pause_all()
1650 {
1651         int i;
1652
1653         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1654                 if ( Audio_streams[i].status == ASF_FREE )
1655                         continue;
1656
1657                 audiostream_pause(i);
1658         }
1659 }
1660
1661 void audiostream_unpause(int i)
1662 {
1663         int is_looping;
1664
1665         if ( i == -1 )
1666                 return;
1667
1668         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
1669         if ( Audio_streams[i].status == ASF_FREE )
1670                 return;
1671
1672         if ( audiostream_is_paused(i) == TRUE ) {
1673                 is_looping = Audio_streams[i].Is_looping();
1674                 audiostream_play(i, -1.0f, is_looping);
1675         }
1676 }
1677
1678 void audiostream_unpause_all()
1679 {
1680         int i;
1681
1682         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
1683                 if ( Audio_streams[i].status == ASF_FREE )
1684                         continue;
1685
1686                 audiostream_unpause(i);
1687         }
1688 }
1689
1690 void audiostream_set_sample_cutoff(int i, uint cutoff)
1691 {
1692 //      STUB_FUNCTION;
1693 }
1694
1695 uint audiostream_get_samples_committed(int i)
1696 {
1697 //      STUB_FUNCTION;
1698
1699         return 0;
1700 }
1701
1702 #endif  // PLAT_UNIX