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