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