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