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