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