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