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