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