|
|
1.1.1.2 root 1: /*
1.1 root 2: * UAE - The Un*x Amiga Emulator
3: *
4: * Win32 interface
5: *
6: * Copyright 1997 Mathias Ortmann
7: */
8:
9: #include <windows.h>
10: #include <ddraw.h>
1.1.1.2 root 11: #include <dsound.h>
1.1 root 12: #include <stdlib.h>
13: #include <stdarg.h>
14: #include <commctrl.h>
15: #include <commdlg.h>
16: #include <stdio.h>
17: #include <fcntl.h>
18: #include <sys/stat.h>
19: #include <io.h>
20:
21: #include "config.h"
22: #include "sysconfig.h"
23: #include "sysdeps.h"
24: #include "options.h"
25: #include "gensound.h"
26: #include "sounddep/sound.h"
27: #include "events.h"
28: #include "uae.h"
29: #include "include/memory.h"
1.1.1.3 ! root 30: #include "events.h"
1.1 root 31: #include "custom.h"
32: #include "osdep/win32gui.h"
1.1.1.2 root 33: #include "osdep/resource.h"
1.1 root 34: #include "osdep/win32.h"
35:
36: /* Sound emulation, Win32 interface */
37: char *sndptr, *sndptrmax, soundneutral;
38:
1.1.1.2 root 39: static WAVEFORMATEX wavfmt;
1.1 root 40:
1.1.1.2 root 41: LPSTR lpData;
42: static frame_time_t basevsynctime;
1.1 root 43: signed long bufsamples;
1.1.1.2 root 44: unsigned int samplecount;
1.1 root 45: DWORD soundbufsize;
46:
1.1.1.2 root 47: int setup_sound (void)
48: {
49: sound_available = 1;
50: return 1;
51: }
52:
53: int use_direct_sound = 1;
54:
55: static HINSTANCE hDSound = NULL;
56:
57: static HRESULT (WINAPI *pDirectSoundCreate) (GUID FAR *, LPDIRECTSOUND FAR *, IUnknown FAR *);
58:
59: extern HWND hAmigaWnd;
60:
61: LPDIRECTSOUND lpDS = NULL;
62: LPDIRECTSOUNDBUFFER lpDSBprimary = NULL;
63: LPDIRECTSOUNDBUFFER lpDSB = NULL;
64:
65: char *DSError( HRESULT error )
1.1 root 66: {
1.1.1.2 root 67: switch( error )
68: {
69: case DSERR_ALLOCATED:
70: return "Allocated";
71:
72: case DSERR_UNINITIALIZED:
73: return "Uninitialized";
74:
75: case DSERR_BADFORMAT:
76: return "Bad Format";
77:
78: case DSERR_INVALIDCALL:
79: return "Invalid Call";
1.1 root 80:
1.1.1.2 root 81: case DSERR_INVALIDPARAM:
82: return "Invalid Parameter";
1.1 root 83:
1.1.1.2 root 84: case DSERR_OUTOFMEMORY:
85: return "Out of Memory";
1.1 root 86:
1.1.1.2 root 87: case DSERR_PRIOLEVELNEEDED:
88: return "Priority Level Needed";
1.1 root 89:
1.1.1.2 root 90: case DSERR_UNSUPPORTED:
91: return "Unsupported";
92:
93: default:
94: return "Unknown";
1.1 root 95: }
96: }
97:
1.1.1.2 root 98: LPWAVEHDR lpWaveHdr;
99: HANDLE hWaveOut;
100:
101: MMTIME mmtime;
102:
103: void close_sound (void)
1.1 root 104: {
1.1.1.2 root 105: if( use_direct_sound )
106: {
107: if( lpDSB )
108: {
109: IDirectSoundBuffer_Release( lpDSB );
110: lpDSB = NULL;
111: }
112: if( lpDSBprimary )
113: {
114: IDirectSoundBuffer_Release( lpDSBprimary );
115: lpDSBprimary = NULL;
116: }
117: if( lpDS )
118: {
119: IDirectSound_Release( lpDS );
120: lpDS = NULL;
121: }
122: if( hDSound )
123: FreeLibrary( hDSound );
124: }
125: else
126: {
127: if( hWaveOut )
128: {
129: waveOutReset( hWaveOut );
130: waveOutUnprepareHeader( hWaveOut, lpWaveHdr, sizeof( WAVEHDR ) );
131: GlobalFree( lpWaveHdr );
132: waveOutClose( hWaveOut );
1.1 root 133:
1.1.1.2 root 134: hWaveOut = NULL;
135: }
136: }
137: GlobalFree( lpData );
138: }
139:
140: static __inline__ void direct_sound_play (LPSTR buffer)
141: {
142: HRESULT hr;
143: LPVOID lpvPtr1, lpvPtr2;
144: DWORD dwBytes1, dwBytes2, status = 0;
145:
146: hr = IDirectSoundBuffer_Lock( lpDSB, 0, soundbufsize, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0 );
147: if( hr == DSERR_BUFFERLOST )
148: {
149: IDirectSoundBuffer_Restore( lpDSB );
150: hr = IDirectSoundBuffer_Lock( lpDSB, 0, soundbufsize, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0 );
151: }
152: if (hr == DS_OK) {
153: memcpy (lpvPtr1, buffer, dwBytes1);
154: if (lpvPtr2 != NULL) {
155: memcpy (lpvPtr2, buffer+dwBytes1, dwBytes2);
156: }
157: hr = IDirectSoundBuffer_Unlock( lpDSB, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2 );
158: hr = IDirectSoundBuffer_SetCurrentPosition( lpDSB, 0 );
159: hr = IDirectSoundBuffer_GetStatus (lpDSB, &status);
160: if (status & DSBSTATUS_PLAYING)
161: {
162: /* Already playing */
163: }
164: else
165: {
166: /* We took too long to fill in the buffer - get it playing again */
167: hr = IDirectSoundBuffer_Play( lpDSB, 0, 0, 0 );
168: if (hr != DS_OK) {
169: write_log( "SoundBuffer_Play() failure: %s", DSError( hr ) );
170: }
171: }
172: }
173: else
174: {
175: write_log( "SoundLock() failure: %s", DSError( hr ) );
176: }
177: }
178:
179: void flush_sound_buffer( void )
180: {
181: if (use_direct_sound)
182: direct_sound_play (lpData);
183: }
184:
185: void startsound( void )
186: {
187: HRESULT hr;
188:
189: if (use_direct_sound)
190: {
191: #if 0
192: hr = IDirectSoundBuffer_Play (lpDSBprimary, 0, 0, DSBPLAY_LOOPING);
193: if (hr != DS_OK) {
194: write_log( "SoundPlay() failure: %s", DSError( hr ) );
195: }
196: hr = IDirectSoundBuffer_Play( lpDSB, 0, 0, 0 );
197:
198: if( hr == DS_OK )
199: {
200: write_log( "Sound Started...\n" );
201: hr = IDirectSoundBuffer_SetVolume( lpDSB, 0 );
202: } else {
203: write_log( "SoundPlay() failure: %s", DSError( hr ) );
204: }
205: #endif
206: }
207: else
208: {
209: lpWaveHdr->lpData = lpData;
210: lpWaveHdr->dwBufferLength = soundbufsize;
211: lpWaveHdr->dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
212: lpWaveHdr->dwLoops = 0x7fffffffL;
213: waveOutPrepareHeader( hWaveOut, lpWaveHdr, sizeof(WAVEHDR) );
214:
215: if( waveOutWrite( hWaveOut, lpWaveHdr, sizeof(WAVEHDR) ) )
216: {
217: write_log( "Failed to write to sound card\n" );
218: }
1.1 root 219: }
220: }
221:
222: void stopsound (void)
223: {
1.1.1.2 root 224: HRESULT hr;
225:
1.1 root 226: sndptr = lpData;
227: samplecount = 0;
1.1.1.2 root 228:
229: if( use_direct_sound )
230: {
231: #if 0
232: hr = IDirectSoundBuffer_Stop( lpDSB );
233: if( hr != DS_OK )
234: {
235: write_log( "SoundStop() failure: %s", DSError( hr ) );
236: }
237: else
238: write_log( "Sound Stopped...\n" );
239: #endif
240: }
241: else
242: {
243: memset( lpData, soundneutral, soundbufsize );
244: waveOutReset( hWaveOut );
245: waveOutUnprepareHeader( hWaveOut, lpWaveHdr, sizeof( WAVEHDR ) );
246: }
247: }
248:
249: static HWND dsound_tmpw;
250:
251: int dsound_newwindow (HWND w)
252: {
253: HRESULT hr;
254:
255: if (lpDS == 0)
256: return 1;
257:
258: if (w == 0)
259: w = dsound_tmpw;
260:
261: hr = IDirectSound_SetCooperativeLevel (lpDS, w, DSSCL_PRIORITY);
262: if (hr != DS_OK) {
263: write_log( "SetCooperativeLevel() failure: %s", DSError (hr));
264: return 0;
265: }
266: return 1;
1.1 root 267: }
268:
269: static int init_sound_win32 (void)
270: {
1.1.1.2 root 271: HRESULT hr;
272: DSBUFFERDESC sound_buffer;
1.1 root 273: MMRESULT mmres;
1.1.1.2 root 274: static int first_time = 1;
1.1 root 275:
1.1.1.2 root 276: if( currprefs.produce_sound < 0 )
277: {
278: currprefs.produce_sound = 0;
279: write_log( "FrameSync disabled.\n" );
280: }
281: else
282: {
283: #ifdef FRAME_RATE_HACK
284: if (first_time)
285: {
286: figure_processor_speed ();
287: first_time = 0;
288: }
1.1 root 289: #endif
290: }
291:
292: if (currprefs.produce_sound < 2) {
1.1.1.2 root 293: write_log ("Sound output disabled.\n");
1.1 root 294: return 1;
295: }
296:
297: wavfmt.wFormatTag = WAVE_FORMAT_PCM;
1.1.1.2 root 298: wavfmt.nChannels = 1 + currprefs.stereo;
1.1 root 299: wavfmt.nSamplesPerSec = currprefs.sound_freq;
300: wavfmt.nBlockAlign = currprefs.sound_bits / 8 * wavfmt.nChannels;
301: wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * currprefs.sound_freq;
302: wavfmt.wBitsPerSample = currprefs.sound_bits;
303:
304: soundneutral = currprefs.sound_bits == 8 ? 128 : 0;
1.1.1.2 root 305: bufsamples = use_direct_sound ? 4096:2048 * currprefs.sound_freq / 11025;
1.1 root 306: soundbufsize = bufsamples * wavfmt.nBlockAlign;
307:
1.1.1.2 root 308: if( !( lpData = (LPSTR)GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, soundbufsize ) ) )
309: {
310: write_log( "Failed to allocate sound buffer!\n" );
311: return 0;
312: }
313:
314: if( use_direct_sound )
315: {
316: hDSound = LoadLibrary( "DSOUND.DLL" );
317: if (hDSound == 0) {
318: write_log ("You have to install DirectX on your system before you can use UAE.\n"
319: "Refer to the documentation for further details.\n");
320: return 0;
321: }
322: pDirectSoundCreate = GetProcAddress (hDSound, "DirectSoundCreate");
323:
324: basevsynctime = vsynctime;
325: sndptrmax = lpData+soundbufsize;
326: hr = pDirectSoundCreate( NULL, &lpDS, NULL );
327: if (hr != DS_OK) {
328: write_log( "DirectSoundCreate() failure: %s", DSError (hr));
329: return 0;
330: }
331:
332: dsound_tmpw = CreateWindowEx (WS_EX_ACCEPTFILES,
333: "PCsuxRox",
334: "Argh",
335: WS_CAPTION,
336: CW_USEDEFAULT, CW_USEDEFAULT,
337: 10, 10,
338: NULL,
339: NULL,
340: 0,
341: NULL);
342:
343: if (! dsound_newwindow (0))
344: return 0;
345:
346: memset (&sound_buffer, 0, sizeof( DSBUFFERDESC ));
347: sound_buffer.dwSize = sizeof( DSBUFFERDESC );
348: sound_buffer.dwFlags = DSBCAPS_PRIMARYBUFFER;
349: sound_buffer.dwBufferBytes = 0;
350: sound_buffer.lpwfxFormat = NULL;
351:
352: hr = IDirectSound_CreateSoundBuffer (lpDS, &sound_buffer, &lpDSBprimary, NULL);
353: if (hr != DS_OK) {
354: write_log( "CreateSoundBuffer() failure: %s", DSError( hr ) );
355: return 0;
356: }
357:
358: hr = IDirectSoundBuffer_SetFormat (lpDSBprimary, &wavfmt);
359: if (hr != DS_OK) {
360: write_log( "SetFormat() failure: %s", DSError (hr));
361: return 0;
362: }
363: #if 0
364: hr = IDirectSoundBuffer_SetVolume (lpDSBprimary, 0);
365: if (hr != DS_OK) {
366: write_log( "SetVolume() 1 failure: %s", DSError (hr));
367: return 0;
368: }
369: #endif
370: sound_buffer.dwBufferBytes = soundbufsize;
371: sound_buffer.lpwfxFormat = &wavfmt;
372: sound_buffer.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC;
373: hr = IDirectSound_CreateSoundBuffer( lpDS, &sound_buffer, &lpDSB, NULL );
374: if (hr != DS_OK) {
375: write_log ("CreateSoundBuffer() failure: %s", DSError (hr));
376: return 0;
377: }
378: hr = IDirectSoundBuffer_SetVolume (lpDSB, 0);
379: if (hr != DS_OK) {
380: write_log( "SetVolume() 2 failure: %s", DSError (hr));
381: return 0;
382: }
383: } else {
384: mmtime.wType = TIME_SAMPLES;
385:
386: if( !( lpWaveHdr = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, (DWORD)sizeof( WAVEHDR ) ) ) )
387: {
388: write_log( "Failed to allocate wave header!\n" );
389: return 0;
390: }
391:
392: if( mmres = waveOutOpen( &hWaveOut, WAVE_MAPPER, &wavfmt, 0, 0, CALLBACK_NULL ) )
393: {
394: write_log( "Sound device failed to open with error code %d.\n", mmres );
395: return 0;
396: }
1.1 root 397: }
398: basevsynctime = vsynctime;
399: sndptrmax = lpData + soundbufsize;
400:
1.1.1.2 root 401: stopsound();
402: startsound();
1.1 root 403:
404: return currprefs.sound_freq;
405: }
406:
407: void adjust_sound_timing (void)
408: {
409: static DWORD last;
410: signed long diff;
411:
1.1.1.2 root 412: if( use_direct_sound )
413: return;
414:
1.1 root 415: waveOutGetPosition (hWaveOut, &mmtime, sizeof (mmtime));
416: if (!mmtime.u.sample)
417: mmtime.u.sample++;
418:
419: if (last == mmtime.u.sample)
420: return;
421: last = mmtime.u.sample;
422:
423: diff = samplecount - mmtime.u.sample;
424:
425: if (diff < -bufsamples || diff > bufsamples) {
426: samplecount = mmtime.u.sample;
427: sndptr = lpData + (samplecount % bufsamples) * wavfmt.nBlockAlign;
428: }
1.1.1.2 root 429:
430: /*
1.1 root 431: if (diff < 0)
432: vsynctime = basevsynctime * 5 / 6;
433: else if (diff > 0)
434: vsynctime = basevsynctime * 7 / 6;
1.1.1.2 root 435: */
436: return;
1.1 root 437: }
438:
439: int init_sound (void)
440: {
441: int rate;
442:
443: if ((rate = init_sound_win32 ()) < 2)
444: return rate;
445:
1.1.1.3 ! root 446: scaled_sample_evtime = (unsigned long) maxhpos * maxvpos * vblank_hz * CYCLE_UNIT / rate;
! 447: scaled_sample_evtime_ok = 1;
1.1 root 448:
449: if (currprefs.sound_bits == 16) {
450: init_sound_table16 ();
1.1.1.2 root 451: sample_handler = currprefs.stereo ? sample16s_handler : sample16_handler;
1.1 root 452: } else {
453: init_sound_table8 ();
1.1.1.2 root 454: sample_handler = currprefs.stereo ? sample8s_handler : sample8_handler;
1.1 root 455: }
456:
1.1.1.2 root 457: write_log ("Sound driver found and configured for %d bits at %d Hz %s\n",
458: currprefs.sound_bits, rate, currprefs.stereo ? "stereo" : "");
1.1 root 459:
460: return 1;
461: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.