]> icculus.org git repositories - taylor/freespace2.git/blob - src/sound/audiostr.cpp
Various 64-bit platform fixes
[taylor/freespace2.git] / src / sound / audiostr.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Sound/AudioStr.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Routines to stream large WAV files from disk
16  *
17  * $Log$
18  * Revision 1.7  2005/03/29 02:18:47  taylor
19  * Various 64-bit platform fixes
20  * Fix compiler errors with MAKE_FS1 and fix gr_set_bitmap() too
21  * Make sure that turrets can fire at asteroids for FS1 (needed for a couple missions)
22  * Streaming audio support (big thanks to Pierre Willenbrock!!)
23  * Removed dependance on strings.tbl for FS1 since we don't actually need it now
24  *
25  * Revision 1.6  2003/08/03 16:10:30  taylor
26  * cleanup; compile warning fixes
27  *
28  * Revision 1.5  2002/06/09 04:41:26  relnev
29  * added copyright header
30  *
31  * Revision 1.4  2002/06/05 04:03:33  relnev
32  * finished cfilesystem.
33  *
34  * removed some old code.
35  *
36  * fixed mouse save off-by-one.
37  *
38  * sound cleanups.
39  *
40  * Revision 1.3  2002/05/27 18:42:50  theoddone33
41  * Fix missing audiostr_* symbols
42  *
43  * Revision 1.2  2002/05/07 03:16:52  theoddone33
44  * The Great Newline Fix
45  *
46  * Revision 1.1.1.1  2002/05/03 03:28:10  root
47  * Initial import.
48  *
49  * 
50  * 5     9/14/99 1:32a Jimb
51  * Commented out Int3() that was hanging Jim's machine.  Happens before
52  * sm2-07 command brief.
53  * 
54  * 4     7/14/99 12:09p Jefff
55  * Make sure we're not servicing a bogus audiostream. Check for "used"
56  * after the critical section lock.
57  * 
58  * 3     12/17/98 4:01p Andsager
59  * up wavedata buffer size to 180000 to allow stereo 16b/22KHz streaming
60  * 
61  * 2     10/07/98 10:53a Dave
62  * Initial checkin.
63  * 
64  * 1     10/07/98 10:51a Dave
65  * 
66  * 53    6/28/98 6:35p Lawrance
67  * move re-entrancy semaphore into audiostream class
68  * 
69  * 52    5/24/98 4:42p Dan
70  * AL: Fix several bugs related to pausing and enabling/disabling event
71  * music
72  * 
73  * 51    5/21/98 11:57a Lawrance
74  * fix potential bug with transitions for music when in packfiles
75  * 
76  * 50    5/15/98 9:09p Lawrance
77  * The last of the multi-threading fixes
78  * 
79  * 49    5/15/98 7:57p Duncan
80  * AL: Fix race condition with music streaming
81  * 
82  * 48    5/15/98 10:13a Lawrance
83  * remove unused audiostream member
84  * 
85  * 47    5/14/98 5:45p Lawrance2
86  * Put critical section around audiostream destroying
87  * 
88  * 46    5/12/98 5:40p Lawrance
89  * Add critical section code to the service buffer call.. since it is
90  * possible to release buffers while in this call
91  * 
92  * 45    5/10/98 3:49p Sandeep
93  * Fix problem with having the audio streaming while trying to close down
94  * sound
95  * 
96  * 44    4/30/98 4:53p John
97  * Restructured and cleaned up cfile code.  Added capability to read off
98  * of CD-ROM drive and out of multiple pack files.
99  * 
100  * 43    4/26/98 3:30a Lawrance
101  * Fix a couple of potential bugs
102  * 
103  * 42    4/21/98 10:18a Dan
104  * 
105  * 41    4/17/98 6:59a John
106  * Changed code the used 'new' and 'delete' to use 'malloc' and 'free'
107  * instead.  Had to manually can constructors/destructors.
108  * 
109  * 40    4/13/98 10:18a John
110  * fixed warnings
111  * 
112  * 39    4/13/98 10:16a John
113  * Switched gettime back to timer_get_milliseconds, which is now thread
114  * safe.
115  * 
116  * 38    4/12/98 11:08p Lawrance
117  * switch back to using gettime() in separate threads
118  * 
119  * 37    4/12/98 5:31p Lawrance
120  * use timer_get_milliseconds() instead of gettime()
121  * 
122  * 36    4/06/98 12:36a Lawrance
123  * Ensure all non-music ADPCM files get decompressed to 8 bit.
124  * 
125  * 35    4/03/98 4:56p Lawrance
126  * Upu the max audio streams to 30
127  * 
128  * 34    3/31/98 4:50p Dan
129  * AL: Clean up all audio streams if necessary in
130  * event_music_level_close()
131  * 
132  * 33    3/23/98 4:12p Lawrance
133  * Fix subtle bug with looping and fading out songs
134  * 
135  * 32    2/18/98 5:49p Lawrance
136  * Even if the ADPCM codec is unavailable, allow game to continue.
137  * 
138  * 31    2/15/98 4:43p Lawrance
139  * work on real-time voice
140  * 
141  * 30    1/19/98 11:37p Lawrance
142  * Fixing Optimization build warnings
143  * 
144  * 29    1/17/98 4:41p Lawrance
145  * Fix problem with multiple audio streams using the same buffers
146  * 
147  * 28    1/16/98 11:49a Lawrance
148  * Use own internal timer for fading.
149  * 
150  * 27    12/28/97 12:43p John
151  * Put in support for reading archive files; Made missionload use the
152  * cf_get_file_list function.   Moved demos directory out of data tree.
153  * 
154  * 26    12/27/97 8:08p Lawrance
155  * If an audiostream doesn't exists, it can't be playing
156  * 
157  * 25    12/18/97 3:30p Lawrance
158  * Fix bug that sometimes caused music with no volume to not get stopped
159  * properly.
160  * 
161  * 24    12/17/97 10:17p Allender
162  * redid streadming code to use mmio* functions instead of cf* functions.
163  * Our functions are not reentrant!
164  * 
165  * 23    12/10/97 10:04p Lawrance
166  * modify what happens in Audio_stream constructor
167  * 
168  * 22    12/09/97 6:14p Lawrance
169  * add -nomusic flag
170  * 
171  * 21    12/08/97 6:21p Lawrance
172  * fix problems with signaling that end-of-file has been reached
173  * 
174  * 20    12/05/97 10:50a Lawrance
175  * improve how silence bytes are written on transitions
176  * 
177  * 19    12/04/97 5:35p Lawrance
178  * fix bug that may have caused errors when writing silence
179  * 
180  * 18    11/28/97 2:09p Lawrance
181  * Overhaul how ADPCM conversion works... use much less memory... safer
182  * too.
183  * 
184  * 17    10/03/97 8:24a Lawrance
185  * When unpausing, be sure to retain looping status
186  * 
187  * 16    9/24/97 5:30p Lawrance
188  * fix bug that was messing up streaming of 8 bit audio
189  * 
190  * 15    9/18/97 10:31p Lawrance
191  * add functions to pause and unpause all audio streams
192  * 
193  * 14    9/09/97 3:39p Sandeep
194  * warning level 4 bugs
195  * 
196  * $NoKeywords: $
197  */
198
199
200 #include "pstypes.h"
201
202 #ifndef PLAT_UNIX
203 #define VC_EXTRALEAN
204 #define STRICT
205 #include <windows.h>
206 #include <mmsystem.h>
207 #include <mmreg.h>
208 #include <msacm.h>
209 #include "vdsound.h"
210 #else
211 #ifdef __APPLE__
212 #include <al.h>
213 #include <alc.h>
214 #include <alut.h>
215 #else
216 #include <AL/al.h>
217 #include <AL/alc.h>
218 #include <AL/alut.h>
219 #endif  // __APPLE__
220 #endif
221 #include "audiostr.h"
222 #include "cfile.h"              // needed for cf_get_path
223 #include "timer.h"
224 #include "sound.h"              /* for Snd_sram */
225 #include "acm.h"
226 #include "ds.h"
227
228
229 #ifdef PLAT_UNIX
230 #ifndef NDEBUG
231 #define OpenAL_ErrorCheck(onerr)        do {            \
232         int i = alGetError();                   \
233         if (i != AL_NO_ERROR) {                 \
234                 while(i != AL_NO_ERROR) {       \
235                         nprintf(("Warning", "%s/%s:%d - OpenAL error %s\n", __FUNCTION__, __FILE__, __LINE__, alGetString(i))); \
236                         i = alGetError();       \
237                 }                               \
238                 onerr;                  \
239         }                                       \
240 } while (0);
241 #else
242 #define OpenAL_ErrorCheck(onerr)
243 #endif
244
245 #define MAX_AL_BUF 4
246
247 #define BYTE byte
248 #define LONG long
249 #define LPBYTE BYTE *
250
251 static int audiostr_read_word(SDL_RWops *rw, WORD *i)
252 {
253         int rc = SDL_RWread( rw, i, 1, sizeof(WORD) );
254
255         if (rc != sizeof(WORD)) {
256                 return 0;
257         }
258
259         *i = INTEL_SHORT(*i);
260
261         return 1;
262 }
263
264 static int audiostr_read_dword(SDL_RWops *rw, DWORD *i)
265 {
266         int rc = SDL_RWread( rw, i, 1, sizeof(DWORD) );
267
268         if (rc != sizeof(DWORD))
269                 return 0;
270
271         *i = INTEL_INT(*i);
272
273         return 1;
274 }
275 #endif
276
277
278 // Constants
279 #ifndef SUCCESS
280 #define SUCCESS TRUE        // Error returns for all member functions
281 #define FAILURE FALSE
282 #endif // SUCCESS
283
284 typedef BOOL (*TIMERCALLBACK)(ptr_u);
285
286 #define BIGBUF_SIZE                                     180000                  // This can be reduced to 88200 once we don't use any stereo
287 //#define BIGBUF_SIZE                                   88300                   // This can be reduced to 88200 once we don't use any stereo
288 unsigned char *Wavedata_load_buffer = NULL;             // buffer used for cueing audiostreams
289 unsigned char *Wavedata_service_buffer = NULL;  // buffer used for servicing audiostreams
290
291 CRITICAL_SECTION Global_service_lock;
292
293 #define COMPRESSED_BUFFER_SIZE  88300
294 unsigned char *Compressed_buffer = NULL;                                // Used to load in compressed data during a cueing interval
295 unsigned char *Compressed_service_buffer = NULL;        // Used to read in compressed data during a service interval
296
297 #define AS_HIGHEST_MAX                          999999999       // max uncompressed filesize supported is 999 meg
298
299 // Classes
300
301 // Timer
302 //
303 // Wrapper class for Windows multimedia timer services. Provides
304 // both periodic and one-shot events. User must supply callback
305 // for periodic events.
306 // 
307
308 class Timer
309 {
310 public:
311     void constructor(void);
312     void destructor(void);
313     BOOL Create (UINT nPeriod, UINT nRes, ptr_u dwUser,  TIMERCALLBACK pfnCallback);
314 protected:
315 #ifndef PLAT_UNIX 
316     static void CALLBACK TimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
317 #else
318     static Uint32 CALLBACK TimeProc(Uint32 interval, void *dwUser);
319 #endif
320     TIMERCALLBACK m_pfnCallback;
321     DWORD m_dwUser;
322     UINT m_nPeriod;
323     UINT m_nRes;
324 #ifndef PLAT_UNIX 
325     UINT m_nIDTimer;
326 #else
327     SDL_TimerID m_nIDTimer;
328 #endif
329 };
330
331
332 // Class
333
334 // WaveFile
335 //
336 // WAV file class (read-only).
337 //
338 // Public Methods:
339 //
340 // Public Data:
341 //   
342 //
343
344 class WaveFile
345 {
346 public:
347         void Init(void);
348         void Close(void);
349         BOOL Open (LPSTR pszFilename);
350         BOOL Cue (void);
351         int     Read (BYTE * pbDest, UINT cbSize, int service=1);
352         UINT GetNumBytesRemaining (void) { return (m_nDataSize - m_nBytesPlayed); }
353         UINT GetUncompressedAvgDataRate (void) { return (m_nUncompressedAvgDataRate); }
354         UINT GetDataSize (void) { return (m_nDataSize); }
355         UINT GetNumBytesPlayed (void) { return (m_nBytesPlayed); }
356         BYTE GetSilenceData (void);
357         WAVEFORMATEX m_wfmt;                                    // format of wave file used by Direct Sound
358         WAVEFORMATEX * m_pwfmt_original;        // foramt of wave file from actual wave source
359         UINT m_total_uncompressed_bytes_read;
360         UINT m_max_uncompressed_bytes_to_read;
361         UINT    m_bits_per_sample_uncompressed;
362
363 protected:
364         UINT m_data_offset;                                             // number of bytes to actual wave data
365         int  m_data_bytes_left;
366 #ifndef PLAT_UNIX 
367         HMMIO   cfp;
368 #else
369         SDL_RWops *cfp;
370 #endif
371
372         UINT m_wave_format;                                             // format of wave source (ie WAVE_FORMAT_PCM, WAVE_FORMAT_ADPCM)
373         UINT m_nBlockAlign;                                             // wave data block alignment spec
374         UINT m_nUncompressedAvgDataRate;                // average wave data rate
375         UINT m_nDataSize;                                                       // size of data chunk
376         UINT m_nBytesPlayed;                                            // offset into data chunk
377         BOOL m_abort_next_read;
378
379 #ifndef PLAT_UNIX 
380         HACMSTREAM              m_hStream;
381         int                             m_hStream_open;
382         WAVEFORMATEX    m_wfxDest;
383 #else
384         void*           m_hStream;
385         int                             m_hStream_open;
386         WAVEFORMATEX    m_wfxDest;
387 #endif
388 };
389
390 // Classes
391
392 // AudioStreamServices
393 //
394 // DirectSound apportions services on a per-window basis to allow
395 // sound from background windows to be muted. The AudioStreamServices
396 // class encapsulates the initialization of DirectSound services.
397 //
398 // Each window that wants to create AudioStream objects must
399 // first create and initialize an AudioStreamServices object. 
400 // All AudioStream objects must be destroyed before the associated 
401 // AudioStreamServices object is destroyed.
402 class AudioStreamServices
403 {
404 public:
405     void Constructor(void);
406     BOOL Initialize ();
407 #ifndef PLAT_UNIX
408     LPDIRECTSOUND GetPDS (void) { return m_pds; }
409 protected:
410     LPDIRECTSOUND m_pds;
411 #endif
412 };
413
414
415 // AudioStream
416 //
417 // Audio stream interface class for playing WAV files using DirectSound.
418 // Users of this class must create AudioStreamServices object before
419 // creating an AudioStream object.
420 //
421 // Public Methods:
422 //
423 // Public Data:
424 //
425
426 // status
427 #define ASF_FREE        0
428 #define ASF_USED        1
429
430 class AudioStream
431 {
432 public:
433         AudioStream (void);
434         ~AudioStream (void);
435         BOOL Create (LPSTR pszFilename, AudioStreamServices * pass);
436         BOOL Destroy (void);
437         void Play (long volume, int looping);
438         int Is_Playing(){ return(m_fPlaying); }
439         int Is_Paused(){ return(m_bIsPaused); }
440         int Is_Past_Limit() { return m_bPastLimit; }
441         void Stop (int paused=0);
442         void Stop_and_Rewind (void);
443         void Fade_and_Destroy (void);
444         void Fade_and_Stop(void);
445         void    Set_Volume(long vol);
446         long    Get_Volume();
447         void    Init_Data();
448         void    Set_Byte_Cutoff(unsigned int num_bytes_cutoff);
449         void  Set_Default_Volume(long converted_volume) { m_lDefaultVolume = converted_volume; }
450         long    Get_Default_Volume() { return m_lDefaultVolume; }
451         unsigned int Get_Bytes_Committed(void);
452         int     Is_looping() { return m_bLooping; }
453         int     status;
454         int     type;
455         UINT m_bits_per_sample_uncompressed;
456
457 protected:
458         void Cue (void);
459         BOOL WriteWaveData (UINT cbSize, UINT* num_bytes_written,int service=1);
460         BOOL WriteSilence (UINT cbSize);
461         DWORD GetMaxWriteSize (void);
462         BOOL ServiceBuffer (void);
463         static BOOL TimerCallback (ptr_u dwUser);
464 #ifdef PLAT_UNIX
465         BOOL GetWritingDone (void);
466 #endif
467
468         AudioStreamServices * m_pass;  // ptr to AudioStreamServices object
469 #ifndef PLAT_UNIX
470         LPDIRECTSOUNDBUFFER m_pdsb;    // ptr to Direct Sound buffer
471 #else
472         ALuint m_al_multichannel_id;   // name of openAL source
473         ALuint m_al_buffer_ids[MAX_AL_BUF]; //names of buffers
474 #endif
475         WaveFile * m_pwavefile;        // ptr to WaveFile object
476         Timer m_timer;              // ptr to Timer object
477         BOOL m_fCued;                  // semaphore (stream cued)
478         BOOL m_fPlaying;               // semaphore (stream playing)
479 #ifndef PLAT_UNIX
480         DSBUFFERDESC m_dsbd;           // Direct Sound buffer description
481 #endif
482         LONG m_lInService;             // reentrancy semaphore
483         UINT m_cbBufOffset;            // last write position
484         UINT m_nBufLength;             // length of sound buffer in msec
485         UINT m_cbBufSize;              // size of sound buffer in bytes
486         UINT m_nBufService;            // service interval in msec
487         UINT m_nTimeStarted;           // time (in system time) playback started
488
489         BOOL    m_bLooping;                                             // whether or not to loop playback
490         BOOL    m_bFade;                                                        // fade out music 
491         BOOL    m_bDestroy_when_faded;
492         LONG  m_lVolume;                                                // volume of stream ( 0 -> -10 000 )
493         LONG    m_lCutoffVolume;
494         BOOL  m_bIsPaused;                                      // stream is stopped, but not rewinded
495         UINT    m_silence_written;                      // number of bytes of silence written to buffer
496         UINT  m_bReadingDone;                           // no more bytes to be read from disk, still have remaining buffer to play
497         DWORD   m_fade_timer_id;                                // timestamp so we know when to start fade
498         DWORD   m_finished_id;                                  // timestamp so we know when we've played #bytes required
499         BOOL    m_bPastLimit;                                   // flag to show we've played past the number of bytes requred
500         LONG    m_lDefaultVolume;
501 #ifdef PLAT_UNIX
502         int m_al_buffer_play;
503 #else
504         HRESULT h_result;
505 #endif
506
507         CRITICAL_SECTION write_lock;
508 };
509
510
511 // AudioStreamServices class implementation
512 //
513 ////////////////////////////////////////////////////////////
514
515 // Constructor
516 void AudioStreamServices::Constructor(void)
517 {
518 #ifndef PLAT_UNIX 
519     // Initialize member data
520     m_pds = NULL;
521
522     // It would seem to make sense to initialize DirectSound here,
523     // but because there could be an error, it's best done in a
524     // separate member function, ::Initialize.
525 #endif
526 }
527
528
529 #ifndef PLAT_UNIX 
530 extern LPDIRECTSOUND pDirectSound;              // From Sound.cpp
531 #endif
532
533
534 // Initialize
535 BOOL AudioStreamServices::Initialize ()
536 {
537     
538     BOOL fRtn = SUCCESS;    // assume success
539
540 #ifndef PLAT_UNIX 
541     if (m_pds == NULL)  {
542                 m_pds = pDirectSound;
543     }
544 #endif
545
546     return (fRtn);
547 }
548
549
550
551 //
552 // AudioStream class implementation
553 //
554 ////////////////////////////////////////////////////////////
555
556 // The following constants are the defaults for our streaming buffer operation.
557 const UINT DefBufferLength          = 2000; // default buffer length in msec
558 const UINT DefBufferServiceInterval = 250;  // default buffer service interval in msec
559
560 // Constructor
561 AudioStream::AudioStream (void)
562 {
563 #ifndef PLAT_UNIX
564         InitializeCriticalSection( &write_lock );
565 #else
566         write_lock = SDL_CreateMutex();
567 #endif
568 }
569
570
571 // Destructor
572 AudioStream::~AudioStream (void)
573 {
574 #ifndef PLAT_UNIX
575         DeleteCriticalSection( &write_lock );
576 #else
577         SDL_DestroyMutex( write_lock );
578 #endif
579 }
580
581
582 void AudioStream::Init_Data ()
583 {
584         m_bLooping = 0;
585         m_bFade = FALSE;
586         m_fade_timer_id = 0;
587         m_finished_id = 0;
588         m_bPastLimit = FALSE;
589         
590         m_bDestroy_when_faded = FALSE;
591         m_lVolume = 0;
592         m_lCutoffVolume = -10000;
593         m_bIsPaused = FALSE;
594         m_silence_written = 0;
595         m_bReadingDone = FALSE;
596
597         m_pwavefile = NULL;
598 #ifndef PLAT_UNIX
599         m_pdsb = NULL;
600 #else
601         memset(m_al_buffer_ids, 0, sizeof(m_al_buffer_ids));
602         m_al_multichannel_id = 0;
603         m_al_buffer_play = 0;
604 #endif
605         m_fPlaying = m_fCued = FALSE;
606         m_lInService = FALSE;
607         m_cbBufOffset = 0;
608         m_nBufLength = DefBufferLength;
609         m_cbBufSize = 0;
610         m_nBufService = DefBufferServiceInterval;
611         m_nTimeStarted = 0;
612 }
613
614 // Create
615 BOOL AudioStream::Create (LPSTR pszFilename, AudioStreamServices * pass)
616 {
617         BOOL fRtn = SUCCESS;    // assume success
618
619         Assert(pszFilename);
620         Assert(pass);
621
622         m_pass = pass;
623         Init_Data();
624
625         if (pszFilename && m_pass) {
626                 // Create a new WaveFile object
627         
628                 m_pwavefile = (WaveFile *)malloc(sizeof(WaveFile));
629                 Assert(m_pwavefile);
630
631                 if (m_pwavefile) {
632                         // Call constructor
633                         m_pwavefile->Init();
634                         // Open given file
635                         m_pwavefile->m_bits_per_sample_uncompressed = m_bits_per_sample_uncompressed;
636                         if (m_pwavefile->Open (pszFilename)) {
637                                 // Calculate sound buffer size in bytes
638 #ifndef PLAT_UNIX
639                                 // Buffer size is average data rate times length of buffer
640                                 // No need for buffer to be larger than wave data though
641                                 m_cbBufSize = (m_pwavefile->GetUncompressedAvgDataRate () * m_nBufLength) / 1000;
642                                 nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
643                                 // m_cbBufSize = (m_cbBufSize > m_pwavefile->GetDataSize ()) ? m_pwavefile->GetDataSize () : m_cbBufSize;
644
645                                 //nprintf(("Sound", "SOUND => average data rate = %d\n\r", m_pwavefile->GetUncompressedAvgDataRate ()));
646                                 //nprintf(("Sound", "SOUND => m_cbBufSize = %d\n\r", m_cbBufSize));
647
648                                 // Create sound buffer
649                                 HRESULT hr;
650                                 memset (&m_dsbd, 0, sizeof (DSBUFFERDESC));
651                                 m_dsbd.dwSize = sizeof (DSBUFFERDESC);
652                                 m_dsbd.dwBufferBytes = m_cbBufSize;
653                                 m_dsbd.lpwfxFormat = &m_pwavefile->m_wfmt;
654                                 m_dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_LOCSOFTWARE;
655
656                                 hr = (m_pass->GetPDS ())->CreateSoundBuffer (&m_dsbd, &m_pdsb, NULL);
657                                 if (hr == DS_OK) {
658                                         // Cue for playback
659                                         Cue ();
660                                         Snd_sram += m_cbBufSize;
661                                 }
662                                 else {
663                                         // Error, unable to create DirectSound buffer
664                                         nprintf(("Sound", "SOUND => Error, unable to create DirectSound buffer\n\r"));
665                                         if (hr == DSERR_BADFORMAT) {
666                                                 nprintf(("Sound", "SOUND => Bad format (probably ADPCM)\n\r"));
667                                         }
668
669                                         fRtn = FAILURE;
670                                 }
671 #else
672
673                                 m_cbBufSize = 
674                                         (m_nBufLength/1000)*
675                                         (m_pwavefile->m_wfmt.wBitsPerSample/8) *
676                                         m_pwavefile->m_wfmt.nChannels*
677                                         m_pwavefile->m_wfmt.nSamplesPerSec;
678 //                              nprintf(("SOUND", "SOUND => Stream buffer created using %d bytes\n", m_cbBufSize));
679                                 // Create sound buffer
680                                 alGenBuffers(MAX_AL_BUF, m_al_buffer_ids);
681                                 
682                                 OpenAL_ErrorCheck(return FAILURE);
683
684                                 alGenSources(1, &m_al_multichannel_id);
685                                 
686                                 OpenAL_ErrorCheck(return FAILURE);
687
688                                 alSourcef(m_al_multichannel_id,AL_ROLLOFF_FACTOR,0);
689
690                                 OpenAL_ErrorCheck(return FAILURE);
691
692                                 alSourcef(m_al_multichannel_id,AL_SOURCE_RELATIVE,AL_TRUE);
693
694                                 OpenAL_ErrorCheck(return FAILURE);
695
696                                 ALfloat posv[] = { 0,0,0 };
697                                 alSourcefv(m_al_multichannel_id,AL_POSITION,posv);
698
699                                 OpenAL_ErrorCheck(return FAILURE);
700
701                                 alSourcef(m_al_multichannel_id,AL_GAIN,1);
702
703                                 OpenAL_ErrorCheck(return FAILURE);
704
705                                 // Cue for playback
706                                 Cue ();
707                                 Snd_sram += m_cbBufSize;
708 #endif
709                         }
710                         else {
711                                 // Error opening file
712                                 nprintf(("SOUND", "SOUND => Failed to open wave file: %s\n\r", pszFilename));
713                                 m_pwavefile->Close();
714                                 free(m_pwavefile);
715                                 m_pwavefile = NULL;
716                                 fRtn = FAILURE;
717                         }   
718                 }
719                 else {
720                         // Error, unable to create WaveFile object
721                         nprintf(("Sound", "SOUND => Failed to create WaveFile object %s\n\r", pszFilename));
722                         fRtn = FAILURE;
723                 }
724         }
725         else {
726                 // Error, passed invalid parms
727                 fRtn = FAILURE;
728         }
729
730         return (fRtn);
731 }
732
733
734 // Destroy
735 BOOL AudioStream::Destroy (void)
736 {
737         BOOL fRtn = SUCCESS;
738
739 #ifndef PLAT_UNIX
740         EnterCriticalSection(&write_lock);
741 #else
742         SDL_LockMutex(write_lock);
743 #endif
744         
745         // Stop playback
746         Stop ();
747
748         // Release DirectSound buffer
749 #ifndef PLAT_UNIX
750         if (m_pdsb) {
751                 m_pdsb->Release ();
752                 m_pdsb = NULL;
753                 Snd_sram -= m_cbBufSize;
754         }
755 #else
756         alDeleteBuffers(MAX_AL_BUF,m_al_buffer_ids);
757         alDeleteSources(1,&m_al_multichannel_id);
758 #endif
759
760         // Delete WaveFile object
761         if (m_pwavefile) {
762                 m_pwavefile->Close();
763                 free(m_pwavefile);
764                 m_pwavefile = NULL;
765         }
766
767         status = ASF_FREE;
768
769 #ifndef PLAT_UNIX
770         LeaveCriticalSection(&write_lock);
771 #else
772         SDL_UnlockMutex(write_lock);
773 #endif
774
775         return fRtn;
776 }
777
778 // WriteWaveData
779 //
780 // Writes wave data to sound buffer. This is a helper method used by Create and
781 // ServiceBuffer; it's not exposed to users of the AudioStream class.
782 BOOL AudioStream::WriteWaveData (UINT size, UINT *num_bytes_written, int service)
783 {
784 #ifndef PLAT_UNIX
785         HRESULT hr;
786         LPBYTE lpbuf1 = NULL;
787         LPBYTE lpbuf2 = NULL;
788         DWORD dwsize1 = 0;
789         DWORD dwsize2 = 0;
790         DWORD dwbyteswritten1 = 0;
791         DWORD dwbyteswritten2 = 0;
792 #endif
793         BOOL fRtn = SUCCESS;
794         unsigned char   *uncompressed_wave_data;
795
796         *num_bytes_written = 0;
797
798         if ( size == 0 || m_bReadingDone ) {
799                 return fRtn;
800         }
801
802 #ifndef PLAT_UNIX
803         if ( !m_pdsb || !m_pwavefile ) {
804                 return fRtn;
805         }
806
807         if ( service ) {
808                 EnterCriticalSection(&Global_service_lock);
809         }
810 #else               
811         if ( (m_al_buffer_ids[0] == 0) || !m_pwavefile ) {
812                 return fRtn;
813         }
814
815         if ( service ) {
816                 SDL_LockMutex(Global_service_lock);
817         }
818 #endif
819                     
820         if ( service ) {
821                 uncompressed_wave_data = Wavedata_service_buffer;
822         } else {
823                 uncompressed_wave_data = Wavedata_load_buffer;
824         }
825
826         int num_bytes_read = 0;
827
828 #ifndef PLAT_UNIX
829     // Lock the sound buffer
830         hr = m_pdsb->Lock (m_cbBufOffset, size, (void**)(&lpbuf1), &dwsize1, (void**)(&lpbuf2), &dwsize2, 0);
831         if (hr == DS_OK) {
832                 // Write data to sound buffer. Because the sound buffer is circular, we may have to
833                 // do two write operations if locked portion of buffer wraps around to start of buffer.
834                 Assert(lpbuf1);
835                 
836                 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, dwsize1+dwsize2,service);
837 #else
838                 num_bytes_read = m_pwavefile->Read(uncompressed_wave_data, m_cbBufSize ,service);
839 #endif
840                 if ( num_bytes_read == -1 ) {
841                         // means nothing left to read!
842                         num_bytes_read = 0;
843                         m_bReadingDone = 1;
844                 }
845
846                 if ( num_bytes_read > 0 ) {
847 #ifndef PLAT_UNIX
848                         if ( (unsigned int)num_bytes_read > dwsize1 ) {
849                                 dwbyteswritten1 = dwsize1;
850                                 dwbyteswritten2 = num_bytes_read - dwsize1;
851
852                                 memcpy(lpbuf1, uncompressed_wave_data, dwsize1);
853                                 Assert(lpbuf2);
854                                 memcpy(lpbuf2, uncompressed_wave_data+dwsize1, num_bytes_read-dwsize1);
855                         } else {
856                                 dwbyteswritten1 = num_bytes_read;
857                                 dwbyteswritten2 = 0;
858                                 memcpy(lpbuf1, uncompressed_wave_data, num_bytes_read);
859                         }
860 #else
861                         nprintf(("SOUND", "SOUND ==> Queueing %d bytes of Data\n", num_bytes_read));
862                         // Lock the sound buffer
863                         ALenum format = AL_FORMAT_MONO8;
864
865                         if (m_pwavefile->m_wfmt.nChannels == 1) {
866                                 if (m_pwavefile->m_wfmt.wBitsPerSample == 8) 
867                                         format = AL_FORMAT_MONO8;
868                                 else if (m_pwavefile->m_wfmt.wBitsPerSample == 16) 
869                                         format = AL_FORMAT_MONO16;
870                         } else if (m_pwavefile->m_wfmt.nChannels == 2) {
871                                 if (m_pwavefile->m_wfmt.wBitsPerSample == 8) 
872                                         format = AL_FORMAT_STEREO8;
873                                 else if (m_pwavefile->m_wfmt.wBitsPerSample == 16) 
874                                         format = AL_FORMAT_STEREO16;
875                         }
876
877                         ALuint bid = 0;
878
879                         alSourceUnqueueBuffers(m_al_multichannel_id,1,&bid);
880                                 
881                         alGetError();
882                         
883                         alBufferData(m_al_buffer_ids[m_al_buffer_play],format,uncompressed_wave_data,num_bytes_read,m_pwavefile->m_wfmt.nSamplesPerSec);
884                         
885                         OpenAL_ErrorCheck(return FAILURE);
886                         
887                         alSourceQueueBuffers(m_al_multichannel_id,1,&m_al_buffer_ids[m_al_buffer_play]);
888                         
889                         OpenAL_ErrorCheck(return FAILURE);
890                         
891                         m_al_buffer_play++;
892
893                         if (m_al_buffer_play>=MAX_AL_BUF)
894                                 m_al_buffer_play = 0;
895                         
896                         m_cbBufOffset = (m_cbBufOffset + num_bytes_read) % m_cbBufSize;
897                         *num_bytes_written = num_bytes_read;
898 #endif
899                 }
900
901 #ifndef PLAT_UNIX                       
902                 // Update our buffer offset and unlock sound buffer
903                 m_cbBufOffset = (m_cbBufOffset + dwbyteswritten1 + dwbyteswritten2) % m_cbBufSize;
904                 *num_bytes_written = dwbyteswritten1 + dwbyteswritten2;
905                 m_pdsb->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
906     }
907         else {
908                 // Error locking sound buffer
909                 nprintf(("SOUND", "SOUND ==> Error, unable to lock sound buffer in AudioStr\n"));
910                 fRtn = FAILURE;
911         }
912 #endif
913
914         if ( service ) {
915 #ifndef PLAT_UNIX
916                 LeaveCriticalSection(&Global_service_lock);
917 #else
918                 SDL_UnlockMutex(Global_service_lock);
919 #endif
920         }
921     
922         return (fRtn);
923 }
924
925 #ifndef PLAT_UNIX 
926
927 // WriteSilence
928 //
929 // Writes silence to sound buffer. This is a helper method used by
930 // ServiceBuffer; it's not exposed to users of the AudioStream class.
931 BOOL AudioStream::WriteSilence (UINT size)
932 {
933         HRESULT hr;
934         LPBYTE lpbuf1 = NULL;
935         LPBYTE lpbuf2 = NULL;
936         DWORD dwsize1 = 0;
937         DWORD dwsize2 = 0;
938         DWORD dwbyteswritten1 = 0;
939         DWORD dwbyteswritten2 = 0;
940         BOOL fRtn = SUCCESS;
941
942         // Lock the sound buffer
943         hr = m_pdsb->Lock (m_cbBufOffset, size, (void**)(&lpbuf1), &dwsize1, (void**)(&lpbuf2), &dwsize2, 0);
944         if (hr == DS_OK) {
945
946                 // Get silence data for this file format. Although word sizes vary for different
947                 // wave file formats, ::Lock will always return pointers on word boundaries.
948                 // Because silence data for 16-bit PCM formats is 0x0000 or 0x00000000, we can
949                 // get away with writing bytes and ignoring word size here.
950                 BYTE bSilence = m_pwavefile->GetSilenceData ();
951         
952                 // Write silence to sound buffer. Because the sound buffer is circular, we may have to
953                 // do two write operations if locked portion of buffer wraps around to start of buffer.
954                 memset (lpbuf1, bSilence, dwsize1);
955                 dwbyteswritten1 = dwsize1;
956             
957      // Second write required?
958                 if (lpbuf2) {
959                         memset (lpbuf2, bSilence, dwsize2);
960                         dwbyteswritten2 = dwsize2;
961                 }
962             
963                 // Update our buffer offset and unlock sound buffer
964                 m_cbBufOffset = (m_cbBufOffset + dwbyteswritten1 + dwbyteswritten2) % m_cbBufSize;
965 //              m_pdsb->Unlock (lpbuf1, dwbyteswritten1, lpbuf2, dwbyteswritten2);
966                 m_pdsb->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
967         }
968         else {
969                 // Error locking sound buffer
970                 nprintf(("SOUND", "SOUND ==> Error, unable to lock sound buffer in AudioStr\n"));
971                 fRtn = FAILURE;
972         }
973
974         return (fRtn);
975 }
976
977 #endif
978
979
980 // GetMaxWriteSize
981 //
982 // Helper function to calculate max size of sound buffer write operation, i.e. how much
983 // free space there is in buffer.
984 DWORD AudioStream::GetMaxWriteSize (void)
985 {
986 #ifndef PLAT_UNIX
987         DWORD dwWriteCursor, dwPlayCursor, dwMaxSize;
988
989         // Get current play position
990         if (m_pdsb->GetCurrentPosition (&dwPlayCursor, &dwWriteCursor) == DS_OK) {
991                 if (m_cbBufOffset <= dwPlayCursor) {
992                         // Our write position trails play cursor
993                         dwMaxSize = dwPlayCursor - m_cbBufOffset;
994                 }
995
996                 else  {// (m_cbBufOffset > dw7Cursor)
997                         // Play cursor has wrapped
998                         dwMaxSize = m_cbBufSize - m_cbBufOffset + dwPlayCursor;
999                 }
1000         }
1001         else {
1002                 // GetCurrentPosition call failed
1003                 Int3();
1004                 dwMaxSize = 0;
1005         }
1006 #else
1007         DWORD dwMaxSize = m_cbBufSize;
1008         ALint n,q;
1009
1010         alGetSourcei(m_al_multichannel_id,AL_BUFFERS_PROCESSED,&n);
1011
1012         OpenAL_ErrorCheck(return 0);
1013
1014         alGetSourcei(m_al_multichannel_id,AL_BUFFERS_QUEUED,&q);
1015
1016         OpenAL_ErrorCheck(return 0);
1017
1018         if (!n && q>=MAX_AL_BUF) //all buffers queued
1019                 dwMaxSize = 0;
1020 #endif
1021
1022 //      nprintf(("Alan","Max write size: %d\n", dwMaxSize));
1023         return (dwMaxSize);
1024 }
1025
1026 #ifdef PLAT_UNIX
1027 // GetWritingDone
1028 //
1029 // Helper function to check if all data is written
1030 BOOL AudioStream::GetWritingDone (void)
1031 {
1032         ALint n;
1033
1034         alGetSourcei(m_al_multichannel_id,AL_BUFFERS_PROCESSED,&n);
1035
1036         OpenAL_ErrorCheck(return 1);
1037
1038         return (n == MAX_AL_BUF); //both buffers processed
1039                
1040 }
1041 #endif
1042
1043 // ServiceBuffer
1044 //
1045 // Routine to service buffer requests initiated by periodic timer.
1046 //
1047 // Returns TRUE if buffer serviced normally; otherwise returns FALSE.
1048 #define FADE_VOLUME_INTERVAL                                                    400             // 100 == 1db
1049 #define VOLUME_ATTENUATION_BEFORE_CUTOFF                        3000            //  12db 
1050 BOOL AudioStream::ServiceBuffer (void)
1051 {
1052         long    vol;
1053         int     fRtn = TRUE;
1054
1055         if ( status != ASF_USED )
1056                 return FALSE;
1057
1058 #ifndef PLAT_UNIX
1059         EnterCriticalSection(&write_lock);
1060 #else
1061         SDL_LockMutex(write_lock);
1062 #endif
1063
1064         // status may have changed, so lets check once again
1065         if ( status != ASF_USED ){
1066 #ifndef PLAT_UNIX
1067                 LeaveCriticalSection(&write_lock);
1068 #else
1069                 SDL_UnlockMutex(write_lock);
1070 #endif
1071                 return FALSE;
1072         }
1073
1074         // Check for reentrance
1075 #ifndef PLAT_UNIX
1076         if (InterlockedExchange (&m_lInService, TRUE) == FALSE) {
1077 #endif
1078                 if ( m_bFade == TRUE ) {
1079                         if ( m_lCutoffVolume == -10000 ) {
1080                                 vol = Get_Volume();
1081 //                              nprintf(("Alan","Volume is: %d\n",vol));
1082                                 m_lCutoffVolume = max(vol - VOLUME_ATTENUATION_BEFORE_CUTOFF, -10000);
1083                         }
1084
1085                         vol = Get_Volume();
1086                         vol = vol - FADE_VOLUME_INTERVAL;       // decrease by 1db
1087 //                      nprintf(("Alan","Volume is now: %d\n",vol));
1088                         Set_Volume(vol);
1089
1090 //                      nprintf(("Sound","SOUND => Volume for stream sound is %d\n",vol));
1091 //                      nprintf(("Alan","Cuttoff Volume is: %d\n",m_lCutoffVolume));
1092                         if ( vol < m_lCutoffVolume ) {
1093                                 m_bFade = 0;
1094                                 m_lCutoffVolume = -10000;
1095                                 if ( m_bDestroy_when_faded == TRUE ) {
1096 #ifndef PLAT_UNIX
1097                                         LeaveCriticalSection(&write_lock);
1098 #else
1099                                         SDL_UnlockMutex(write_lock);
1100 #endif
1101                                         Destroy();      
1102                                         // Reset reentrancy semaphore
1103 #ifndef PLAT_UNIX
1104                                         InterlockedExchange (&m_lInService, FALSE);
1105 #endif
1106                                         return FALSE;
1107                                 }
1108                                 else {
1109                                         Stop_and_Rewind();
1110                                         // Reset reentrancy semaphore
1111 #ifndef PLAT_UNIX
1112                                         LeaveCriticalSection(&write_lock);
1113                                         InterlockedExchange (&m_lInService, FALSE);
1114 #else
1115                                         SDL_UnlockMutex(write_lock);
1116 #endif
1117                                         return TRUE;
1118                                 }
1119                         }
1120                 }
1121
1122                 // All of sound not played yet, send more data to buffer
1123                 DWORD dwFreeSpace = GetMaxWriteSize ();
1124
1125                 // Determine free space in sound buffer
1126                 if (dwFreeSpace) {
1127
1128                         // Some wave data remains, but not enough to fill free space
1129                         // Send wave data to buffer, fill remainder of free space with silence
1130                         uint num_bytes_written;
1131
1132                         if (WriteWaveData (dwFreeSpace, &num_bytes_written) == SUCCESS) {
1133 //                              nprintf(("Alan","Num bytes written: %d\n", num_bytes_written));
1134
1135                                 if ( m_pwavefile->m_total_uncompressed_bytes_read >= m_pwavefile->m_max_uncompressed_bytes_to_read ) {
1136                                         m_fade_timer_id = timer_get_milliseconds() + 1700;              // start fading 1.7 seconds from now
1137                                         m_finished_id = timer_get_milliseconds() + 2000;                // 2 seconds left to play out buffer
1138                                         m_pwavefile->m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1139                                 }
1140
1141                                 if ( (m_fade_timer_id>0) && ((uint)timer_get_milliseconds() > m_fade_timer_id) ) {
1142                                         m_fade_timer_id = 0;
1143                                         Fade_and_Stop();
1144                                 }
1145
1146                                 if ( (m_finished_id>0) && ((uint)timer_get_milliseconds() > m_finished_id) ) {
1147                                         m_finished_id = 0;
1148                                         m_bPastLimit = TRUE;
1149                                 }
1150
1151 #ifndef PLAT_UNIX
1152                                 if ( (num_bytes_written < dwFreeSpace) && m_bReadingDone ) {
1153                                         int num_bytes_silence;
1154                                         num_bytes_silence = dwFreeSpace - num_bytes_written;
1155
1156                                         if ( num_bytes_silence > 0 ) {
1157
1158                                                 m_silence_written += num_bytes_silence;
1159                                                 if (WriteSilence (num_bytes_silence) == FAILURE)        {
1160                                                         fRtn = FALSE;
1161                                                         Int3();
1162                                                 }
1163
1164                                                 if ( m_silence_written >= m_cbBufSize ) {
1165                                                         m_silence_written = 0;
1166 #else
1167                                 if ( m_bReadingDone && GetWritingDone()) {
1168 #endif
1169
1170                                                         if ( m_bDestroy_when_faded == TRUE ) {
1171 #ifndef PLAT_UNIX
1172                                                                 LeaveCriticalSection(&write_lock);
1173 #else
1174                                                                 SDL_UnlockMutex(write_lock);
1175 #endif
1176                                                                 Destroy();
1177                                                                 // Reset reentrancy semaphore
1178 #ifndef PLAT_UNIX
1179                                                                 InterlockedExchange (&m_lInService, FALSE);
1180 #endif
1181                                                                 return FALSE;
1182                                                         }
1183
1184                                                         // All of sound has played, stop playback or loop again
1185                                                         if ( m_bLooping && !m_bFade) {
1186                                                                 Play(m_lVolume, m_bLooping);
1187                                                         }
1188                                                         else {
1189                                                                 Stop_and_Rewind();
1190                                                         }
1191 #ifndef PLAT_UNIX
1192                                                 }
1193                                         }
1194 #endif
1195                                 }
1196                         }
1197                         else {
1198                                 // Error writing wave data
1199                                 fRtn = FALSE;
1200                                 Int3(); 
1201                         }
1202                 }
1203 #ifndef PLAT_UNIX
1204         // Reset reentrancy semaphore
1205         InterlockedExchange (&m_lInService, FALSE);
1206     } else {
1207                 // Service routine reentered. Do nothing, just return
1208                 fRtn = FALSE;
1209     }
1210
1211         LeaveCriticalSection(&write_lock);
1212 #endif
1213
1214 #ifdef PLAT_UNIX
1215         SDL_UnlockMutex(write_lock);
1216 #endif
1217
1218         return (fRtn);
1219 }
1220
1221 // Cue
1222 void AudioStream::Cue (void)
1223 {
1224         UINT num_bytes_written;
1225
1226         if (!m_fCued) {
1227                 m_bFade = FALSE;
1228                 m_fade_timer_id = 0;
1229                 m_finished_id = 0;
1230                 m_bPastLimit = FALSE;
1231                 m_lVolume = 0;
1232                 m_lCutoffVolume = -10000;
1233
1234                 m_bDestroy_when_faded = FALSE;
1235
1236                 // Reset buffer ptr
1237                 m_cbBufOffset = 0;
1238
1239                 // Reset file ptr, etc
1240                 m_pwavefile->Cue ();
1241
1242 #ifndef PLAT_UNIX
1243                 // Reset DirectSound buffer
1244                 m_pdsb->SetCurrentPosition (0);
1245 #else
1246                 // Unqueue all buffers
1247                 alSourceUnqueueBuffers(m_al_multichannel_id,MAX_AL_BUF,m_al_buffer_ids);
1248 #endif
1249
1250                 // Fill buffer with wave data
1251                 WriteWaveData (m_cbBufSize, &num_bytes_written,0);
1252
1253                 m_fCued = TRUE;
1254         }
1255 }
1256
1257
1258 // Play
1259 void AudioStream::Play (long volume, int looping)
1260 {
1261 #ifndef PLAT_UNIX
1262         if (m_pdsb) {
1263 #else
1264         if (m_al_buffer_ids[0] != 0) {
1265 #endif
1266                 // If playing, stop
1267                 if (m_fPlaying) {
1268                         if ( m_bIsPaused == FALSE)
1269                         Stop_and_Rewind();
1270                 }
1271
1272                 // Cue for playback if necessary
1273                 if (!m_fCued) {
1274                         Cue ();
1275                 }
1276
1277                 if ( looping )
1278                         m_bLooping = 1;
1279                 else
1280                         m_bLooping = 0;
1281
1282 #ifndef PLAT_UNIX
1283                 // Begin DirectSound playback
1284                 HRESULT hr = m_pdsb->Play (0, 0, DSBPLAY_LOOPING);
1285                 if (hr == DS_OK) {
1286 #else
1287                 alSourcePlay(m_al_multichannel_id);
1288                 
1289                 OpenAL_ErrorCheck(return);
1290 #endif
1291                         m_nTimeStarted = timer_get_milliseconds();
1292                         Set_Volume(volume);
1293                         // Kick off timer to service buffer
1294                         m_timer.constructor();
1295
1296                         m_timer.Create (m_nBufService, m_nBufService, ptr_u (this), TimerCallback);
1297
1298                         // Playback begun, no longer cued
1299                         m_fPlaying = TRUE;
1300                         m_bIsPaused = FALSE;
1301 #ifndef PLAT_UNIX
1302                 }
1303                 else {
1304                         // If the buffer was lost, try to restore it
1305                         if ( hr == DSERR_BUFFERLOST ) {
1306                                 hr = m_pdsb->Restore();
1307                                 if ( hr == DS_OK ) {
1308                                         hr = m_pdsb->Play (0, 0, DSBPLAY_LOOPING);
1309                                 }
1310                                 else {
1311                                         nprintf(("Sound", "Sound => Lost a buffer, tried restoring but got %s\n", get_DSERR_text(hr) ));
1312                                         Int3(); // get Alan, he wants to see this
1313                                 }
1314                         }
1315
1316                         if ( hr != DS_OK ) {
1317                                 nprintf(("Sound", "Sound => Play failed with return value %s\n", get_DSERR_text(hr) ));
1318                         }
1319                 }
1320 #endif
1321         }
1322 }
1323
1324 // Timer callback for Timer object created by ::Play method.
1325 BOOL AudioStream::TimerCallback (ptr_u dwUser)
1326 {
1327     // dwUser contains ptr to AudioStream object
1328     AudioStream * pas = (AudioStream *) dwUser;
1329
1330     return (pas->ServiceBuffer ());
1331 }
1332
1333 void AudioStream::Set_Byte_Cutoff(unsigned int byte_cutoff)
1334 {
1335         if ( m_pwavefile == NULL )
1336                 return;
1337
1338         m_pwavefile->m_max_uncompressed_bytes_to_read = byte_cutoff;
1339 }
1340
1341 unsigned int AudioStream::Get_Bytes_Committed(void)
1342 {
1343         if ( m_pwavefile == NULL )
1344                 return 0;
1345
1346         return m_pwavefile->m_total_uncompressed_bytes_read;
1347 }
1348
1349
1350 // Fade_and_Destroy
1351 void AudioStream::Fade_and_Destroy (void)
1352 {
1353         m_bFade = TRUE;
1354         m_bDestroy_when_faded = TRUE;
1355 }
1356
1357 // Fade_and_Destroy
1358 void AudioStream::Fade_and_Stop (void)
1359 {
1360         m_bFade = TRUE;
1361         m_bDestroy_when_faded = FALSE;
1362 }
1363
1364
1365 // Stop
1366 void AudioStream::Stop(int paused)
1367 {
1368         if (m_fPlaying) {
1369                 // Stop DirectSound playback
1370 #ifndef PLAT_UNIX
1371                 m_pdsb->Stop ();
1372 #else
1373                 if (paused) {
1374                         alSourcePause(m_al_multichannel_id);
1375                 } else {
1376                         alSourceStop(m_al_multichannel_id);
1377                 }
1378 #endif
1379                 m_fPlaying = FALSE;
1380                 m_bIsPaused = paused;
1381
1382                 // Delete Timer object
1383                 m_timer.destructor();
1384         }
1385 }
1386
1387 // Stop_and_Rewind
1388 void AudioStream::Stop_and_Rewind (void)
1389 {
1390         if (m_fPlaying) {
1391                 // Stop DirectSound playback
1392 #ifndef PLAT_UNIX
1393                 m_pdsb->Stop ();
1394 #else
1395                 alSourceStop(m_al_multichannel_id);
1396                 OpenAL_ErrorCheck(return);
1397 #endif
1398
1399                 // Delete Timer object
1400                 m_timer.destructor();
1401
1402                 m_fPlaying = FALSE;
1403         }
1404
1405         m_fCued = FALSE;        // this will cause wave file to start from beginning
1406         m_bReadingDone = FALSE;
1407 }
1408
1409 // Set_Volume
1410 void AudioStream::Set_Volume(long vol)
1411 {
1412         if ( vol < -10000 )
1413                 vol = -10000;
1414         
1415         if ( vol > 0 )
1416                 vol = 0;
1417
1418         Assert( vol >= -10000 && vol <= 0 );
1419
1420 #ifndef PLAT_UNIX
1421         h_result = m_pdsb->SetVolume(vol);
1422 #else
1423         ALfloat alvol = (vol != -10000) ? pow(10.0, (float)vol / (-600.0 / log10(.5))): 0.0;
1424
1425         alSourcef(m_al_multichannel_id,AL_GAIN,alvol);
1426 #endif
1427
1428         m_lVolume = vol;
1429
1430 #ifndef PLAT_UNIX
1431         if ( h_result != DS_OK )
1432                 nprintf(("Sound","SOUND => SetVolume() failed with code '%s'\n", get_DSERR_text(h_result) ));
1433 #endif
1434 }
1435
1436
1437 // Get_Volume
1438 long AudioStream::Get_Volume()
1439 {
1440         return m_lVolume;
1441 }
1442
1443 // constructor
1444 void Timer::constructor(void)
1445 {
1446         m_nIDTimer = NULL;
1447 #ifdef PLAT_UNIX
1448         SDL_InitSubSystem(SDL_INIT_TIMER);
1449 #endif
1450 }
1451
1452
1453 // Destructor
1454 void Timer::destructor(void)
1455 {
1456         if (m_nIDTimer) {
1457 #ifndef PLAT_UNIX
1458                 timeKillEvent (m_nIDTimer);
1459 #else
1460                 SDL_RemoveTimer (m_nIDTimer);
1461 #endif
1462                 m_nIDTimer = NULL;
1463         }
1464 }
1465
1466
1467 // Create
1468 BOOL Timer::Create (UINT nPeriod, UINT nRes, ptr_u dwUser, TIMERCALLBACK pfnCallback)
1469 {
1470         BOOL bRtn = SUCCESS;    // assume success
1471
1472         Assert(pfnCallback);
1473         Assert(nPeriod > 10);
1474         Assert(nPeriod >= nRes);
1475
1476         m_nPeriod = nPeriod;
1477         m_nRes = nRes;
1478         m_dwUser = dwUser;
1479         m_pfnCallback = pfnCallback;
1480
1481 #ifndef PLAT_UNIX
1482         if ((m_nIDTimer = timeSetEvent (m_nPeriod, m_nRes, TimeProc, (DWORD) this, TIME_PERIODIC)) == NULL) {
1483 #else
1484         if ((m_nIDTimer = SDL_AddTimer (m_nPeriod, TimeProc, (void*) this)) == NULL) {
1485             nprintf(("SOUND", "SOUND ==> Error, unable to create timer\n"));
1486 #endif
1487           bRtn = FAILURE;
1488         }
1489
1490         return (bRtn);
1491 }
1492
1493
1494 // Timer proc for multimedia timer callback set with timeSetTime().
1495 //
1496 // Calls procedure specified when Timer object was created. The 
1497 // dwUser parameter contains "this" pointer for associated Timer object.
1498 // 
1499 #ifndef PLAT_UNIX
1500 void CALLBACK Timer::TimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
1501 #else
1502 Uint32 CALLBACK Timer::TimeProc(Uint32 interval, void *dwUser)
1503 #endif
1504 {
1505     // dwUser contains ptr to Timer object
1506     Timer * ptimer = (Timer *) dwUser;
1507
1508     // Call user-specified callback and pass back user specified data
1509     (ptimer->m_pfnCallback) (ptimer->m_dwUser);
1510 #ifdef PLAT_UNIX
1511     if (ptimer->m_nPeriod)
1512         return interval;
1513     else {
1514         SDL_RemoveTimer(ptimer->m_nIDTimer);
1515         ptimer->m_nIDTimer = NULL;
1516         return 0;
1517     }
1518 #endif
1519 }
1520
1521
1522 // WaveFile class implementation
1523 //
1524 ////////////////////////////////////////////////////////////
1525
1526 // Constructor
1527 void WaveFile::Init(void)
1528 {
1529         // Init data members
1530         m_data_offset = 0;
1531         cfp = NULL;
1532         m_pwfmt_original = NULL;
1533         m_nBlockAlign= 0;
1534         m_nUncompressedAvgDataRate = 0;
1535         m_nDataSize = 0;
1536         m_nBytesPlayed = 0;
1537         m_total_uncompressed_bytes_read = 0;
1538         m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1539
1540         m_hStream_open = 0;
1541         m_abort_next_read = FALSE;
1542 }
1543
1544 // Destructor
1545 void WaveFile::Close(void)
1546 {
1547         // Free memory
1548         if (m_pwfmt_original) {
1549                 free(m_pwfmt_original);
1550                 m_pwfmt_original = NULL;
1551         }
1552
1553         if ( m_hStream_open ) {
1554                 ACM_stream_close((void*)m_hStream);
1555                 m_hStream_open = 0;
1556         }
1557
1558         // Close file
1559         if (cfp) {
1560 #ifndef PLAT_UNIX
1561                 mmioClose( cfp, 0 );
1562 #else
1563                 SDL_RWclose(cfp);
1564 #endif
1565                 cfp = NULL;
1566         }
1567 }
1568
1569
1570 // Open
1571 BOOL WaveFile::Open (LPSTR pszFilename)
1572 {
1573         int done = FALSE;
1574         WORD cbExtra = 0;
1575         BOOL fRtn = SUCCESS;    // assume success
1576         PCMWAVEFORMAT pcmwf;
1577         char fullpath[_MAX_PATH];
1578
1579         m_total_uncompressed_bytes_read = 0;
1580         m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1581
1582         int FileSize, FileOffset;
1583
1584         if ( !cf_find_file_location(pszFilename, CF_TYPE_ANY, fullpath, &FileSize, &FileOffset ))       {
1585                 goto OPEN_ERROR;
1586         }
1587
1588 #ifndef PLAT_UNIX
1589         cfp = mmioOpen(fullpath, NULL, MMIO_ALLOCBUF | MMIO_READ);
1590 #else
1591         cfp = SDL_RWFromFile(fullpath, "rb");
1592 #endif
1593
1594         if ( cfp == NULL ) {
1595                 goto OPEN_ERROR;
1596         }
1597
1598         // Skip the "RIFF" tag and file size (8 bytes)
1599         // Skip the "WAVE" tag (4 bytes)
1600 #ifndef PLAT_UNIX
1601         mmioSeek( cfp, 12+FileOffset, SEEK_SET );
1602 #else
1603         SDL_RWseek( cfp, 12+FileOffset, SEEK_SET );
1604 #endif
1605         // Now read RIFF tags until the end of file
1606         uint tag, size, next_chunk;
1607
1608         while(done == FALSE)    {
1609 #ifndef PLAT_UNIX
1610                 if ( mmioRead(cfp, (char *)&tag, sizeof(uint)) != sizeof(uint) )
1611 #else
1612                 if ( SDL_RWread(cfp, &tag, 1, sizeof(uint)) != sizeof(uint) )
1613 #endif
1614                         break;
1615
1616                 tag = INTEL_INT( tag );
1617
1618 #ifndef PLAT_UNIX
1619                 if ( mmioRead(cfp, (char *)&size, sizeof(uint)) != sizeof(uint) )
1620 #else
1621                 if ( SDL_RWread(cfp, &size, 1, sizeof(uint)) != sizeof(uint) )
1622 #endif
1623                         break;
1624
1625                 size = INTEL_INT( size );
1626
1627 #ifndef PLAT_UNIX
1628                 next_chunk = mmioSeek( cfp, 0, SEEK_CUR );
1629 #else
1630                 next_chunk = SDL_RWtell( cfp );
1631 #endif
1632                 next_chunk += size;
1633
1634                 switch( tag )   {
1635                 case 0x20746d66:                // The 'fmt ' tag
1636 #ifndef PLAT_UNIX
1637                         mmioRead( cfp, (char *)&pcmwf, sizeof(PCMWAVEFORMAT) );
1638                         if ( pcmwf.wf.wFormatTag != WAVE_FORMAT_PCM ) {
1639                                 mmioRead( cfp, (char *)&cbExtra, sizeof(short) );
1640                         }
1641 #else
1642                         audiostr_read_word(cfp, &pcmwf.wf.wFormatTag);
1643                         audiostr_read_word(cfp, &pcmwf.wf.nChannels);
1644                         audiostr_read_dword(cfp, &pcmwf.wf.nSamplesPerSec);
1645                         audiostr_read_dword(cfp, &pcmwf.wf.nAvgBytesPerSec);
1646                         audiostr_read_word(cfp, &pcmwf.wf.nBlockAlign);
1647                         audiostr_read_word(cfp, &pcmwf.wBitsPerSample);
1648
1649                         if ( pcmwf.wf.wFormatTag != WAVE_FORMAT_PCM ) {
1650                                 audiostr_read_word(cfp, &cbExtra);
1651                         }
1652 #endif
1653
1654                         // Allocate memory for WAVEFORMATEX structure + extra bytes
1655                         if ( (m_pwfmt_original = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){
1656                                 Assert(m_pwfmt_original != NULL);
1657                                 // Copy bytes from temporary format structure
1658                                 memcpy (m_pwfmt_original, &pcmwf, sizeof(pcmwf));
1659                                 m_pwfmt_original->cbSize = cbExtra;
1660
1661                                 // Read those extra bytes, append to WAVEFORMATEX structure
1662                                 if (cbExtra != 0) {
1663 #ifndef PLAT_UNIX
1664                                         mmioRead( cfp, (char *)((ubyte *)(m_pwfmt_original) + sizeof(WAVEFORMATEX)), cbExtra );
1665 #else
1666                                         SDL_RWread( cfp, ((ubyte *)(m_pwfmt_original) + sizeof(WAVEFORMATEX)), 1, cbExtra );
1667 #endif
1668                                 }
1669                         }
1670                         else {
1671                                 Int3();         // malloc failed
1672                                 goto OPEN_ERROR;
1673                         }       
1674                         break;
1675
1676                 case 0x61746164:                // the 'data' tag
1677                         m_nDataSize = size;     // This is size of data chunk.  Compressed if ADPCM.
1678                         m_data_bytes_left = size;
1679 #ifndef PLAT_UNIX
1680                         m_data_offset = mmioSeek( cfp, 0, SEEK_CUR);
1681 #else
1682                         m_data_offset = SDL_RWtell( cfp );
1683 #endif
1684                         done = TRUE;
1685                         break;
1686
1687                 default:        // unknown, skip it
1688                         break;
1689                 }       // end switch
1690
1691 #ifndef PLAT_UNIX
1692                 mmioSeek( cfp, next_chunk, SEEK_SET );
1693 #else
1694                 SDL_RWseek( cfp, next_chunk, SEEK_SET );
1695 #endif
1696         }
1697
1698         // At this stage, examine source format, and set up WAVEFORATEX structure for DirectSound.
1699         // Since DirectSound only supports PCM, force this structure to be PCM compliant.  We will
1700         // need to convert data on the fly later if our souce is not PCM
1701         switch ( m_pwfmt_original->wFormatTag ) {
1702                 case WAVE_FORMAT_PCM:
1703                         m_wave_format = WAVE_FORMAT_PCM;
1704                         m_wfmt.wBitsPerSample = m_pwfmt_original->wBitsPerSample;
1705                         break;
1706
1707                 case WAVE_FORMAT_ADPCM:
1708                         m_wave_format = WAVE_FORMAT_ADPCM;
1709                         m_wfmt.wBitsPerSample = 16;
1710                         m_bits_per_sample_uncompressed = 16;
1711                         break;
1712
1713                 default:
1714                         nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n"));
1715                         //Int3();
1716                         goto OPEN_ERROR;
1717                         break;
1718
1719         } // end switch
1720             
1721         // Set up the WAVEFORMATEX structure to have the right PCM characteristics
1722         m_wfmt.wFormatTag = WAVE_FORMAT_PCM;
1723         m_wfmt.nChannels = m_pwfmt_original->nChannels;
1724         m_wfmt.nSamplesPerSec = m_pwfmt_original->nSamplesPerSec;
1725         m_wfmt.cbSize = 0;
1726         m_wfmt.nBlockAlign = (unsigned short)(( m_wfmt.nChannels * m_wfmt.wBitsPerSample ) / 8);
1727         m_wfmt.nAvgBytesPerSec = m_wfmt.nBlockAlign * m_wfmt.nSamplesPerSec;
1728
1729         // Init some member data from format chunk
1730         m_nBlockAlign = m_pwfmt_original->nBlockAlign;
1731         m_nUncompressedAvgDataRate = m_wfmt.nAvgBytesPerSec;
1732
1733         // Cue for streaming
1734         Cue ();
1735  
1736         // Successful open
1737         goto OPEN_DONE;
1738     
1739 OPEN_ERROR:
1740         // Handle all errors here
1741         nprintf(("SOUND","SOUND ==> Could not open wave file %s for streaming\n",pszFilename));
1742
1743         fRtn = FAILURE;
1744         if (cfp != NULL) {
1745                 // Close file
1746 #ifndef PLAT_UNIX
1747                 mmioClose( cfp, 0 );
1748 #else
1749                 SDL_RWclose( cfp );
1750 #endif
1751                 cfp = NULL;
1752         }
1753         if (m_pwfmt_original)
1754         {
1755                 free(m_pwfmt_original);
1756                 m_pwfmt_original = NULL;
1757         }
1758
1759 OPEN_DONE:
1760         return (fRtn);
1761 }
1762
1763
1764 // Cue
1765 //
1766 // Set the file pointer to the start of wave data
1767 //
1768 BOOL WaveFile::Cue (void)
1769 {
1770         BOOL fRtn = SUCCESS;    // assume success
1771         int rval;
1772
1773         m_total_uncompressed_bytes_read = 0;
1774         m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;
1775
1776 #ifndef PLAT_UNIX
1777         rval = mmioSeek( cfp, m_data_offset, SEEK_SET );
1778 #else
1779         rval = SDL_RWseek( cfp, m_data_offset, SEEK_SET );
1780 #endif
1781         if ( rval == -1 ) {
1782                 fRtn = FAILURE;
1783         }
1784
1785         m_data_bytes_left = m_nDataSize;
1786         m_abort_next_read = FALSE;
1787
1788         return fRtn;
1789 }
1790
1791
1792 // Read
1793 //
1794 // Returns number of bytes actually read.
1795 // 
1796 //      Returns -1 if there is nothing more to be read.  This function can return 0, since
1797 // sometimes the amount of bytes requested is too small for the ACM decompression to 
1798 // locate a suitable block
1799 int WaveFile::Read(BYTE *pbDest, UINT cbSize, int service)
1800 {
1801         unsigned char   *dest_buf=NULL, *uncompressed_wave_data;
1802         int                             rc, uncompressed_bytes_written;
1803         unsigned int    src_bytes_used, convert_len, num_bytes_desired=0, num_bytes_read;
1804
1805 //      nprintf(("Alan","Reqeusted: %d\n", cbSize));
1806
1807
1808         if ( service ) {
1809                 uncompressed_wave_data = Wavedata_service_buffer;
1810         } else {
1811                 uncompressed_wave_data = Wavedata_load_buffer;
1812         }
1813
1814         switch ( m_wave_format ) {
1815                 case WAVE_FORMAT_PCM:
1816                         num_bytes_desired = cbSize;
1817                         dest_buf = pbDest;
1818                         break;
1819
1820                 case WAVE_FORMAT_ADPCM:
1821                         if ( !m_hStream_open ) {
1822                                 if ( !ACM_stream_open(m_pwfmt_original, &m_wfxDest, (void**)&m_hStream, m_bits_per_sample_uncompressed)  ) {
1823                                         m_hStream_open = 1;
1824                                 } else {
1825                                         Int3();
1826                                         return -1;
1827                                 }
1828                         }
1829
1830                         num_bytes_desired = cbSize;
1831         
1832                         if ( service ) {
1833                                 dest_buf = Compressed_service_buffer;
1834                         } else {
1835                                 dest_buf = Compressed_buffer;
1836                         }
1837
1838                         if ( num_bytes_desired <= 0 ) {
1839                                 num_bytes_desired = 0;
1840 //                              nprintf(("Alan","No bytes required for ADPCM time interval\n"));
1841                         } else {
1842                                 num_bytes_desired = ACM_query_source_size((void*)m_hStream, cbSize);
1843 //                              nprintf(("Alan","Num bytes desired: %d\n", num_bytes_desired));
1844                         }
1845                         break;
1846
1847                 default:
1848                         nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n"));
1849                         Int3();
1850                         return -1;
1851                         break;
1852
1853         } // end switch
1854                 
1855         num_bytes_read = 0;
1856         convert_len = 0;
1857         src_bytes_used = 0;
1858
1859         // read data from disk
1860         if ( m_data_bytes_left <= 0 ) {
1861                 num_bytes_read = 0;
1862                 uncompressed_bytes_written = 0;
1863                 return -1;
1864         }
1865
1866         if ( m_data_bytes_left > 0 && num_bytes_desired > 0 ) {
1867                 int actual_read;
1868
1869                 if ( num_bytes_desired <= (unsigned int)m_data_bytes_left ) {
1870                         num_bytes_read = num_bytes_desired;
1871                 }
1872                 else {
1873                         num_bytes_read = m_data_bytes_left;
1874                 }
1875
1876 #ifndef PLAT_UNIX
1877                 actual_read = mmioRead( cfp, (char *)dest_buf, num_bytes_read );
1878 #else
1879                 actual_read = SDL_RWread( cfp, dest_buf, 1, num_bytes_read );
1880 #endif
1881                 if ( (actual_read <= 0) || (m_abort_next_read) ) {
1882                         num_bytes_read = 0;
1883                         uncompressed_bytes_written = 0;
1884                         return -1;
1885                 }
1886
1887                 if ( num_bytes_desired >= (unsigned int)m_data_bytes_left ) {
1888                         m_abort_next_read = 1;                  
1889                 }
1890
1891                 num_bytes_read = actual_read;
1892         }
1893
1894         // convert data if necessary, to PCM
1895         if ( m_wave_format == WAVE_FORMAT_ADPCM ) {
1896                 if ( num_bytes_read > 0 ) {
1897                                 rc = ACM_convert((void*)m_hStream, dest_buf, num_bytes_read, uncompressed_wave_data, BIGBUF_SIZE, &convert_len, &src_bytes_used);
1898                                 if ( rc == -1 ) {
1899                                         goto READ_ERROR;
1900                                 }
1901                                 if ( convert_len == 0 ) {
1902                                         Int3();
1903                                         goto READ_ERROR;
1904                                 }
1905                 }
1906
1907                 Assert(src_bytes_used <= num_bytes_read);
1908                 if ( src_bytes_used < num_bytes_read ) {
1909                         // seek back file pointer to reposition before unused source data
1910 #ifndef PLAT_UNIX
1911                         mmioSeek(cfp, src_bytes_used - num_bytes_read, SEEK_CUR);
1912 #else
1913                         SDL_RWseek( cfp, src_bytes_used - num_bytes_read, SEEK_CUR );
1914 #endif
1915                 }
1916
1917                 // Adjust number of bytes left
1918                 m_data_bytes_left -= src_bytes_used;
1919                 m_nBytesPlayed += src_bytes_used;
1920                 uncompressed_bytes_written = convert_len;
1921
1922                 // Successful read, keep running total of number of data bytes read
1923                 goto READ_DONE;
1924         }
1925         else {
1926                 // Successful read, keep running total of number of data bytes read
1927                 // Adjust number of bytes left
1928                 m_data_bytes_left -= num_bytes_read;
1929                 m_nBytesPlayed += num_bytes_read;
1930                 uncompressed_bytes_written = num_bytes_read;
1931                 goto READ_DONE;
1932         }
1933     
1934 READ_ERROR:
1935         num_bytes_read = 0;
1936         uncompressed_bytes_written = 0;
1937
1938 READ_DONE:
1939         m_total_uncompressed_bytes_read += uncompressed_bytes_written;
1940 //      nprintf(("Alan","Read: %d\n", uncompressed_bytes_written));
1941         return (uncompressed_bytes_written);
1942 }
1943
1944
1945 #ifndef PLAT_UNIX
1946 // GetSilenceData
1947 //
1948 // Returns 8 bits of data representing silence for the Wave file format.
1949 //
1950 // Since we are dealing only with PCM format, we can fudge a bit and take
1951 // advantage of the fact that for all PCM formats, silence can be represented
1952 // by a single byte, repeated to make up the proper word size. The actual size
1953 // of a word of wave data depends on the format:
1954 //
1955 // PCM Format       Word Size       Silence Data
1956 // 8-bit mono       1 byte          0x80
1957 // 8-bit stereo     2 bytes         0x8080
1958 // 16-bit mono      2 bytes         0x0000
1959 // 16-bit stereo    4 bytes         0x00000000
1960 //
1961 BYTE WaveFile::GetSilenceData (void)
1962 {
1963         BYTE bSilenceData = 0;
1964
1965         // Silence data depends on format of Wave file
1966         if (m_pwfmt_original) {
1967                 if (m_wfmt.wBitsPerSample == 8) {
1968                         // For 8-bit formats (unsigned, 0 to 255)
1969                         // Packed DWORD = 0x80808080;
1970                         bSilenceData = 0x80;
1971                 }
1972                 else if (m_wfmt.wBitsPerSample == 16) {
1973                         // For 16-bit formats (signed, -32768 to 32767)
1974                         // Packed DWORD = 0x00000000;
1975                         bSilenceData = 0x00;
1976                 }
1977                 else {
1978                         Int3();
1979                         return -1;
1980                 }
1981         }
1982         else {
1983                 Int3();
1984                 return -1;
1985         }
1986
1987         return (bSilenceData);
1988 }
1989
1990 #endif
1991
1992 AudioStreamServices * m_pass = NULL;   // ptr to AudioStreamServices object
1993
1994 #define MAX_AUDIO_STREAMS       30
1995 AudioStream Audio_streams[MAX_AUDIO_STREAMS];
1996
1997 int Audiostream_inited = 0;
1998
1999 void audiostream_init()
2000 {
2001         if ( Audiostream_inited == 1 )
2002                 return;
2003                 
2004         int i;
2005
2006         if ( !ACM_is_inited() ) {
2007                 return;
2008         }
2009
2010         // Create and initialize AudioStreamServices object.
2011         // This must be done once and only once for each window that uses
2012         // streaming services.
2013         m_pass = (AudioStreamServices *)malloc(sizeof(AudioStreamServices));
2014
2015         if (m_pass)     {
2016                 m_pass->Constructor();
2017                 m_pass->Initialize();
2018 #ifndef PLAT_UNIX
2019                 if ( !pDirectSound ) {
2020                         return;
2021                 }
2022 #endif
2023         }
2024
2025         // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
2026         // disk during a load/cue
2027         if ( Wavedata_load_buffer == NULL ) {
2028                 Wavedata_load_buffer = (unsigned char*)malloc(BIGBUF_SIZE);
2029                 Assert(Wavedata_load_buffer != NULL);
2030         }
2031
2032         // Allocate memory for the buffer which holds the uncompressed wave data that is streamed from the
2033         // disk during a service interval
2034         if ( Wavedata_service_buffer == NULL ) {
2035                 Wavedata_service_buffer = (unsigned char*)malloc(BIGBUF_SIZE);
2036                 Assert(Wavedata_service_buffer != NULL);
2037         }
2038
2039         // Allocate memory for the buffer which holds the compressed wave data that is read from the hard disk
2040         if ( Compressed_buffer == NULL ) {
2041                 Compressed_buffer = (unsigned char*)malloc(COMPRESSED_BUFFER_SIZE);
2042                 Assert(Compressed_buffer != NULL);
2043         }
2044
2045         if ( Compressed_service_buffer == NULL ) {
2046                 Compressed_service_buffer = (unsigned char*)malloc(COMPRESSED_BUFFER_SIZE);
2047                 Assert(Compressed_service_buffer != NULL);
2048         }
2049
2050         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2051                 Audio_streams[i].Init_Data();
2052                 Audio_streams[i].status = ASF_FREE;
2053                 Audio_streams[i].type = ASF_NONE;
2054         }
2055
2056 #ifndef PLAT_UNIX
2057         InitializeCriticalSection( &Global_service_lock );
2058 #else
2059         Global_service_lock = SDL_CreateMutex( );
2060 #endif
2061
2062         Audiostream_inited = 1;
2063 }
2064
2065 // Close down the audiostream system.  Must call audiostream_init() before any audiostream functions can
2066 // be used.
2067 void audiostream_close()
2068 {
2069         if ( Audiostream_inited == 0 )
2070                 return;
2071
2072         int i;
2073
2074         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2075                 if ( Audio_streams[i].status == ASF_USED ) {
2076                         Audio_streams[i].status = ASF_FREE;
2077                         Audio_streams[i].Destroy();
2078                 }
2079         }
2080
2081         // Destroy AudioStreamServices object
2082         if (m_pass)     {
2083                 free(m_pass);
2084                 m_pass = NULL;
2085         }
2086
2087         // free global buffers
2088         if ( Wavedata_load_buffer ) {
2089                 free(Wavedata_load_buffer);
2090                 Wavedata_load_buffer = NULL;
2091         }
2092
2093         if ( Wavedata_service_buffer ) {
2094                 free(Wavedata_service_buffer);
2095                 Wavedata_service_buffer = NULL;
2096         }
2097
2098         if ( Compressed_buffer ) {
2099                 free(Compressed_buffer);
2100                 Compressed_buffer = NULL;
2101         }
2102
2103         if ( Compressed_service_buffer ) {
2104                 free(Compressed_service_buffer);
2105                 Compressed_service_buffer = NULL;
2106         }
2107
2108 #ifndef PLAT_UNIX
2109         DeleteCriticalSection( &Global_service_lock );
2110 #else
2111         SDL_DestroyMutex( Global_service_lock );
2112 #endif
2113         Audiostream_inited = 0;
2114 }
2115
2116 // Open a digital sound file for streaming
2117 //
2118 // input:       filename        =>      disk filename of sound file
2119 //                              type            => what type of audio stream do we want to open:
2120 //                                                                      ASF_SOUNDFX
2121 //                                                                      ASF_EVENTMUSIC
2122 //                                                                      ASF_VOICE
2123 //      
2124 // returns:     success => handle to identify streaming sound
2125 //                              failure => -1
2126 int audiostream_open( char * filename, int type )
2127 {
2128
2129         int i, rc;
2130         if (!Audiostream_inited || !snd_is_inited())
2131                 return -1;
2132
2133         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2134                 if ( Audio_streams[i].status == ASF_FREE ) {
2135                         Audio_streams[i].status = ASF_USED;
2136                         Audio_streams[i].type = type;
2137                         break;
2138                 }
2139         }
2140
2141         if ( i == MAX_AUDIO_STREAMS ) {
2142                 nprintf(("Sound", "SOUND => No more audio streams available!\n"));
2143                 return -1;
2144         }
2145
2146         switch(type) {
2147         case ASF_VOICE:
2148         case ASF_SOUNDFX:
2149                 Audio_streams[i].m_bits_per_sample_uncompressed = 8;
2150                 break;
2151         case ASF_EVENTMUSIC:
2152                 Audio_streams[i].m_bits_per_sample_uncompressed = 16;
2153                 break;
2154         default:
2155                 Int3();
2156                 return -1;
2157         }
2158         
2159         rc = Audio_streams[i].Create(filename, m_pass);
2160         if ( rc == 0 ) {
2161                 Audio_streams[i].status = ASF_FREE;
2162                 return -1;
2163         }
2164         else
2165                 return i;
2166 }
2167
2168
2169 void audiostream_close_file(int i, int fade)
2170 {
2171         if (!Audiostream_inited)
2172                 return;
2173
2174         if ( i == -1 )
2175                 return;
2176
2177         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2178
2179         if ( Audio_streams[i].status == ASF_USED ) {
2180                 if ( fade == TRUE ) {
2181                         Audio_streams[i].Fade_and_Destroy();
2182                 }
2183                 else {
2184                         Audio_streams[i].Destroy();
2185                 }
2186         }
2187 }
2188
2189 void audiostream_close_all(int fade)
2190 {
2191         int i;
2192
2193         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2194                 if ( Audio_streams[i].status == ASF_FREE )
2195                         continue;
2196
2197                 audiostream_close_file(i, fade);
2198         }
2199 }
2200
2201 extern int ds_convert_volume(float volume);
2202
2203 void audiostream_play(int i, float volume, int looping)
2204 {
2205         if (!Audiostream_inited)
2206                 return;
2207
2208         if ( i == -1 )
2209                 return;
2210
2211         Assert(looping >= 0);
2212         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2213
2214         // convert from 0->1 to -10000->0 for volume
2215         int converted_volume;
2216         if ( volume == -1 ) {
2217                 converted_volume = Audio_streams[i].Get_Default_Volume();
2218         }
2219         else {
2220                 Assert(volume >= 0.0f && volume <= 1.0f );
2221                 converted_volume = ds_convert_volume(volume);
2222         }
2223
2224         Assert( Audio_streams[i].status == ASF_USED );
2225         Audio_streams[i].Set_Default_Volume(converted_volume);
2226         Audio_streams[i].Play(converted_volume, looping);
2227 }
2228
2229 void audiostream_stop(int i, int rewind, int paused)
2230 {
2231         if (!Audiostream_inited) return;
2232
2233         if ( i == -1 )
2234                 return;
2235
2236         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2237         Assert( Audio_streams[i].status == ASF_USED );
2238
2239         if ( rewind )
2240                 Audio_streams[i].Stop_and_Rewind();
2241         else
2242                 Audio_streams[i].Stop(paused);
2243 }
2244
2245 int audiostream_is_playing(int i)
2246 {
2247         if ( i == -1 )
2248                 return 0;
2249
2250         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2251         if ( Audio_streams[i].status != ASF_USED )
2252                 return 0;
2253
2254         return Audio_streams[i].Is_Playing();
2255 }
2256
2257
2258 void audiostream_set_volume_all(float volume, int type)
2259 {
2260         int i;
2261
2262         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2263                 if ( Audio_streams[i].status == ASF_FREE )
2264                         continue;
2265
2266                 if ( Audio_streams[i].type == type ) {
2267                         int converted_volume;
2268                         converted_volume = ds_convert_volume(volume);
2269                         Audio_streams[i].Set_Volume(converted_volume);
2270                 }
2271         }
2272 }
2273
2274
2275 void audiostream_set_volume(int i, float volume)
2276 {
2277         if ( i == -1 )
2278                 return;
2279
2280         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2281         Assert( volume >= 0 && volume <= 1);
2282
2283         if ( Audio_streams[i].status == ASF_FREE )
2284                 return;
2285
2286         int converted_volume;
2287         converted_volume = ds_convert_volume(volume);
2288         Audio_streams[i].Set_Volume(converted_volume);
2289 }
2290
2291
2292 int audiostream_is_paused(int i)
2293 {
2294         if ( i == -1 )
2295                 return 0;
2296
2297         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2298         if ( Audio_streams[i].status == ASF_FREE )
2299                 return -1;
2300
2301         BOOL is_paused;
2302         is_paused = Audio_streams[i].Is_Paused();
2303         return is_paused;
2304 }
2305
2306
2307 void audiostream_set_byte_cutoff(int i, unsigned int cutoff)
2308 {
2309         if ( i == -1 )
2310                 return;
2311
2312         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2313         Assert( cutoff > 0 );
2314
2315         if ( Audio_streams[i].status == ASF_FREE )
2316                 return;
2317
2318         Audio_streams[i].Set_Byte_Cutoff(cutoff);
2319 }
2320
2321
2322 unsigned int audiostream_get_bytes_committed(int i)
2323 {
2324         if ( i == -1 )
2325                 return 0;
2326
2327         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2328
2329         if ( Audio_streams[i].status == ASF_FREE )
2330                 return 0;
2331
2332         unsigned int num_bytes_committed;
2333         num_bytes_committed = Audio_streams[i].Get_Bytes_Committed();
2334         return num_bytes_committed;
2335 }
2336
2337 int audiostream_done_reading(int i)
2338 {
2339         if ( i == -1 )
2340                 return 0;
2341
2342         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2343
2344         if ( Audio_streams[i].status == ASF_FREE )
2345                 return 0;
2346
2347         int done_reading;
2348         done_reading = Audio_streams[i].Is_Past_Limit();
2349         return done_reading;
2350 }
2351
2352
2353 int audiostream_is_inited()
2354 {
2355         return Audiostream_inited;
2356 }
2357
2358 // pause a single audio stream, indentified by handle i.
2359 void audiostream_pause(int i)
2360 {
2361         if ( i == -1 )
2362                 return;
2363
2364         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2365         if ( Audio_streams[i].status == ASF_FREE )
2366                 return;
2367
2368         if ( audiostream_is_playing(i) == TRUE ) {
2369                 audiostream_stop(i, 0, 1);
2370         }
2371 }
2372
2373 // pause all audio streams that are currently playing.
2374 void audiostream_pause_all()
2375 {
2376         int i;
2377
2378         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2379                 if ( Audio_streams[i].status == ASF_FREE )
2380                         continue;
2381
2382                 audiostream_pause(i);
2383         }
2384 }
2385
2386 // unpause the audio stream identified by handle i.
2387 void audiostream_unpause(int i)
2388 {
2389         if ( i == -1 )
2390                 return;
2391
2392         int is_looping;
2393
2394         Assert( i >= 0 && i < MAX_AUDIO_STREAMS );
2395         if ( Audio_streams[i].status == ASF_FREE )
2396                 return;
2397
2398         if ( audiostream_is_paused(i) == TRUE ) {
2399                 is_looping = Audio_streams[i].Is_looping();
2400                 audiostream_play(i, -1.0f, is_looping);
2401         }
2402 }
2403
2404 // unpause all audio streams that are currently paused
2405 void audiostream_unpause_all()
2406 {
2407         int i;
2408
2409         for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) {
2410                 if ( Audio_streams[i].status == ASF_FREE )
2411                         continue;
2412
2413                 audiostream_unpause(i);
2414         }
2415 }
2416