1 //============================================================================
2 //
3 // SSSS tt lll lll
4 // SS SS tt ll ll
5 // SS tttttt eeee ll ll aaaa
6 // SSSS tt ee ee ll ll aa
7 // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8 // SS SS tt ee ll ll aa aa
9 // SSSS ttt eeeee llll llll aaaaa
10 //
11 // Copyright (c) 1995-1998 by Bradford W. Mott
12 //
13 // See the file "license" for information on usage and redistribution of
14 // this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 //
16 // $Id: SndXBOX.cxx,v 1.1.1.1 2001/12/27 19:54:32 bwmott Exp $
17 //============================================================================
18
19
20 #include "SndXBOX.hxx"
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27
28 int get_mixingactive();
29 unsigned char* updatemixing_xbox( unsigned int todo );
30 void writexbox( char *msg ) ;
31
32 #ifdef __cplusplus
33 }
34 #endif
35
36 // the local buffer is what the stream buffer feeds from
37 // note that this needs to be large enough to buffer at frameskip 11
38 // for 30fps games like Tapper; we will scale the value down based
39 // on the actual framerate of the game
40 #define MAX_BUFFER_SIZE (128 * 1024 * 4)
41
42 // this is the maximum number of extra samples we will ask for
43 // per frame (I know this looks like a lot, but most of the
44 // time it will generally be nowhere close to this)
45 #define MAX_SAMPLE_ADJUST 16
46
47 extern DWORD g_dwStartTime ;
48 extern DWORD g_dwTimePaused ;
49
50 /**
51 Compute the buffer size to use based on the given sample rate
52
53 @param The sample rate to compute the buffer size for
54 */
computeBufferSize(int sampleRate)55 static unsigned long computeBufferSize(int sampleRate)
56 {
57 int t;
58
59 for(t = 7; t <= 12; ++t)
60 {
61 if((1 << t) > (sampleRate / 60))
62 {
63 return (1 << (t - 1));
64 }
65 }
66
67 return 256;
68 }
69
70 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundXBOX()71 SoundXBOX::SoundXBOX()
72 {
73 dsound = NULL ;
74 stream_buffer = NULL ;
75 attenuation = 0 ;
76 samples_to_read = 0 ;
77 m_fps = 60 ;
78
79
80 }
81
82 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
~SoundXBOX()83 SoundXBOX::~SoundXBOX()
84 {
85 }
86
dsound_init(void)87 int SoundXBOX::dsound_init(void)
88 {
89 HRESULT result;
90
91
92 current_adjustment = 0 ;
93 m_totalBytesWritten = 0 ;
94
95 // make a format description for what we want
96 stream_format.wBitsPerSample = 16;
97 stream_format.wFormatTag = WAVE_FORMAT_PCM;
98 stream_format.nChannels = 1;
99 stream_format.nSamplesPerSec = 44100;
100 stream_format.nBlockAlign = stream_format.wBitsPerSample * stream_format.nChannels / 8;
101 stream_format.nAvgBytesPerSec = stream_format.nSamplesPerSec * stream_format.nBlockAlign;
102
103 // compute the buffer sizes
104 stream_buffer_size = (UINT64)MAX_BUFFER_SIZE ;
105 // stream_buffer_size = ((UINT64)MAX_BUFFER_SIZE * (UINT64)stream_format.nSamplesPerSec) / 44100;
106 stream_buffer_size = (stream_buffer_size * stream_format.nBlockAlign) / 4;
107 stream_buffer_size = (stream_buffer_size * 30) / 60 ;
108 //stream_buffer_size = (stream_buffer_size / 1024) * 1024;
109 //stream_buffer_size = (stream_buffer_size / 2940) * 2940;
110 stream_buffer_size = 2940*6;
111
112 stream_buffer_in = 0 ;
113
114 DSMIXBINVOLUMEPAIR dsmbvp[8] = {
115 {DSMIXBIN_FRONT_LEFT, DSBVOLUME_MAX}, // left channel
116 {DSMIXBIN_FRONT_RIGHT, DSBVOLUME_MAX}, // right channel
117 {DSMIXBIN_FRONT_CENTER, DSBVOLUME_MAX}, // left channel
118 {DSMIXBIN_FRONT_CENTER, DSBVOLUME_MAX}, // right channel
119 {DSMIXBIN_BACK_LEFT, DSBVOLUME_MAX}, // left channel
120 {DSMIXBIN_BACK_RIGHT, DSBVOLUME_MAX}, // right channel
121 {DSMIXBIN_LOW_FREQUENCY, DSBVOLUME_MAX}, // left channel
122 {DSMIXBIN_LOW_FREQUENCY, DSBVOLUME_MAX}}; // right channel
123
124 DSMIXBINS dsmb;
125 dsmb.dwMixBinCount = 8;
126 dsmb.lpMixBinVolumePairs = dsmbvp;
127
128 // create a buffer desc for the stream buffer
129 stream_desc.dwSize = sizeof(stream_desc);
130 stream_desc.dwFlags = 0 ;
131 stream_desc.dwBufferBytes = 0; //we'll specify our own data
132 // stream_desc.dwBufferBytes = stream_buffer_size;
133 stream_desc.lpwfxFormat = &stream_format;
134 stream_desc.lpMixBins = &dsmb;
135
136 // create the stream buffer
137 if ((result = dsound->CreateSoundBuffer(&stream_desc, &stream_buffer, NULL)) != DS_OK)
138 {
139 stream_buffer = NULL ;
140 return 1 ;
141 }
142
143 m_pSoundBufferData = (byte*)malloc( stream_buffer_size ) ;
144
145 stream_buffer->SetBufferData( m_pSoundBufferData, stream_buffer_size ) ;
146 stream_buffer->SetPlayRegion( 0, stream_buffer_size ) ;
147 stream_buffer->SetLoopRegion( 0, stream_buffer_size ) ;
148
149 memset( m_pSoundBufferData, 0, stream_buffer_size);
150
151 //m_mixbuf = (signed short*)malloc( ( (44100/60) * 2 * 2 ) + 100 ) ;
152
153 stream_buffer->SetVolume( DSBVOLUME_MAX );
154 stream_buffer->SetCurrentPosition( 0 ) ;
155
156 m_dwWritePos = 0 ;
157 return 0 ;
158 }
159
160
init()161 void SoundXBOX::init( )
162 {
163 m_totalBytesWritten = 0 ;
164 m_dwWritePos = 0 ;
165 //m_dwWritePos = stream_buffer_size - 35025 ; //half second ahead
166 memset( m_pSoundBufferData, 0, stream_buffer_size ) ;
167 stream_buffer->SetVolume( DSBVOLUME_MAX );
168 DWORD dwStatus;
169
170 stream_buffer->StopEx( 0, DSBSTOPEX_IMMEDIATE );
171 do
172 {
173 stream_buffer->GetStatus( &dwStatus );
174 } while( dwStatus & DSBSTATUS_PLAYING );
175 stream_buffer->SetCurrentPosition( 0 ) ;
176 m_bDanger = 0 ;
177 m_dwOldTick = GetTickCount() ;
178 m_nVolume = DSBVOLUME_MAX ;
179 }
180
adjust_volume(int volchange)181 void SoundXBOX::adjust_volume( int volchange )
182 {
183 m_nVolume += volchange ;
184
185 if ( m_nVolume > DSBVOLUME_MAX )
186 m_nVolume = DSBVOLUME_MAX ;
187 if ( m_nVolume < DSBVOLUME_MIN )
188 m_nVolume = DSBVOLUME_MIN ;
189
190 stream_buffer->SetVolume( m_nVolume ) ;
191
192 }
193
cleanup()194 void SoundXBOX::cleanup()
195 {
196 DWORD dwStatus;
197
198 stream_buffer->SetVolume( DSBVOLUME_MIN );
199
200 stream_buffer->StopEx( 0, DSBSTOPEX_IMMEDIATE );
201 do
202 {
203 stream_buffer->GetStatus( &dwStatus );
204 } while( dwStatus & DSBSTATUS_PLAYING );
205 }
insertSilence(int samples)206 void SoundXBOX::insertSilence( int samples )
207 {
208 unsigned int datalen ;
209 DWORD bytesToEnd ;
210
211
212 return ;
213
214 datalen = samples ;
215
216
217 bytesToEnd = stream_buffer_size - m_dwWritePos ;
218
219 if ( datalen > bytesToEnd )
220 {
221 memset( m_pSoundBufferData + m_dwWritePos, 0, bytesToEnd ) ;
222 memset( m_pSoundBufferData, 0, datalen - bytesToEnd ) ;
223 }
224 else
225 {
226 memset( m_pSoundBufferData + m_dwWritePos, 0, datalen ) ;
227 }
228
229 m_dwWritePos = ( m_dwWritePos + datalen ) % stream_buffer_size ;
230
231 m_totalBytesWritten += datalen ;
232
233
234
235 }
236
process(int isThrottled)237 int SoundXBOX::process( int isThrottled )
238 {
239 static int firsttime = 1 ;
240 static FILE *outfile ;
241 unsigned char *sndbuf ;
242 unsigned char mybuf[6*4096] ;
243 short *src ;
244 short *dst ;
245 int datalen ;
246 DWORD playPos ;
247 DWORD bytesToEnd ;
248 DWORD distWritePlay ;
249
250
251
252
253 //if ( firsttime )
254 //{
255 //firsttime = 0 ;
256 //outfile = fopen( "d:\\out.wav", "wb" ) ;
257 //}
258
259 if ( get_mixingactive() == 0 )
260 return 0 ;
261
262 stream_buffer->GetCurrentPosition( &playPos, NULL ) ;
263
264 if ( m_dwWritePos > playPos )
265 {
266 distWritePlay = m_dwWritePos - playPos ;
267 }
268 else
269 {
270 distWritePlay = ( stream_buffer_size - playPos ) + m_dwWritePos ;
271 }
272
273 if ( distWritePlay > 4096*3 )
274 return 0 ;
275
276
277 datalen = 4096 ;
278
279 sndbuf = updatemixing_xbox( datalen ) ;
280
281 if ( sndbuf == NULL )
282 return 0 ;
283
284 src = (short*)sndbuf ;
285 dst = (short*)mybuf ;
286
287 for ( int i = 0 ; i < datalen/2 ; i++ )
288 {
289 *dst++ = (((*src++)*-1)<<1) ;
290 //*dst++ = *src++;
291 }
292
293 sndbuf = (unsigned char*)mybuf ;
294
295 //fwrite( sndbuf, 2940, 1, outfile ) ;
296 //fflush(outfile) ;
297
298 bytesToEnd = stream_buffer_size - m_dwWritePos ;
299
300 if ( datalen > bytesToEnd )
301 {
302 memcpy( m_pSoundBufferData + m_dwWritePos, sndbuf, bytesToEnd ) ;
303 memcpy( m_pSoundBufferData, sndbuf + bytesToEnd, datalen - bytesToEnd ) ;
304 }
305 else
306 {
307 memcpy( m_pSoundBufferData + m_dwWritePos, sndbuf, datalen ) ;
308 }
309
310 m_dwWritePos = ( m_dwWritePos + datalen ) % stream_buffer_size ;
311
312 m_totalBytesWritten += datalen ;
313
314
315 if ( distWritePlay < datalen )
316 {
317 //m_bDanger = 1 ;
318 return 1 ;
319 }
320
321 m_bDanger = 0 ;
322
323 return 0 ;
324 }
325 /*
326 int SoundXBOX::process( int isThrottled )
327 {
328 unsigned char sndbuf[4*1024] ;
329 int num_written ;
330 int datalen ;
331 float numtowrite_f ;
332 int numtowrite ;
333 float waittime ;
334 DWORD waittime_ms ;
335 float elapsedTime ;
336 DWORD playPos ;
337 DWORD bytesToEnd ;
338 DWORD distWritePlay ;
339 DWORD newWritePos ;
340
341
342
343
344 datalen = 526 ;
345
346
347 do
348 {
349 stream_buffer->GetCurrentPosition( &playPos, NULL ) ;
350
351 if ( m_dwWritePos > playPos )
352 {
353 distWritePlay = m_dwWritePos - playPos ;
354 }
355 else
356 {
357 distWritePlay = ( stream_buffer_size - playPos ) + m_dwWritePos ;
358 }
359 } while ( ( distWritePlay > 1500 ) && ( !isThrottled ) );
360
361
362 bytesToEnd = stream_buffer_size - m_dwWritePos ;
363
364 if ( datalen > bytesToEnd )
365 {
366 memcpy( m_pSoundBufferData + m_dwWritePos, sndbuf, bytesToEnd ) ;
367 memcpy( m_pSoundBufferData, sndbuf + bytesToEnd, datalen - bytesToEnd ) ;
368 }
369 else
370 {
371 memcpy( m_pSoundBufferData + m_dwWritePos, sndbuf, datalen ) ;
372 }
373
374 m_dwWritePos = ( m_dwWritePos + datalen ) % stream_buffer_size ;
375
376 m_totalBytesWritten += datalen ;
377
378
379 if ( distWritePlay < 5000 )
380 {
381 //m_bDanger = 1 ;
382 return 1 ;
383 }
384
385 m_bDanger = 0 ;
386
387 return 0 ;
388 }
389 */
390 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
391 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pause(bool state)392 void SoundXBOX::pause(bool state)
393 {
394 DWORD dwStatus;
395
396 if (stream_buffer)
397 {
398 if (state)
399 {
400 stream_buffer->StopEx( 0, DSBSTOPEX_IMMEDIATE );
401 do
402 {
403 stream_buffer->GetStatus( &dwStatus );
404 } while( dwStatus & DSBSTATUS_PLAYING );
405 }
406 else
407 stream_buffer->Play( 0, 0, DSBPLAY_LOOPING ) ;
408 }
409 }
410
411