c62d2810 |
1 | /* FCE Ultra - NES/Famicom Emulator\r |
2 | *\r |
3 | * Copyright notice for this file:\r |
4 | * Copyright (C) 2002 Ben Parnell\r |
5 | *\r |
6 | * This program is free software; you can redistribute it and/or modify\r |
7 | * it under the terms of the GNU General Public License as published by\r |
8 | * the Free Software Foundation; either version 2 of the License, or\r |
9 | * (at your option) any later version.\r |
10 | *\r |
11 | * This program is distributed in the hope that it will be useful,\r |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of\r |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r |
14 | * GNU General Public License for more details.\r |
15 | *\r |
16 | * You should have received a copy of the GNU General Public License\r |
17 | * along with this program; if not, write to the Free Software\r |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r |
19 | */\r |
20 | \r |
21 | FILE *soundlog=0;\r |
22 | void WriteWaveData(int32 *Buffer, int Count);\r |
23 | DWORD WINAPI DSThread(LPVOID lpParam);\r |
24 | LPDIRECTSOUND ppDS=0;\r |
25 | LPDIRECTSOUNDBUFFER ppbuf=0;\r |
26 | LPDIRECTSOUNDBUFFER ppbufsec=0;\r |
27 | LPDIRECTSOUNDBUFFER ppbufw;\r |
28 | \r |
29 | DSBUFFERDESC DSBufferDesc;\r |
30 | WAVEFORMATEX wfa;\r |
31 | WAVEFORMATEX wf;\r |
32 | \r |
33 | static int DSBufferSize=0;\r |
34 | static int bittage;\r |
35 | \r |
36 | void TrashSound(void)\r |
37 | {\r |
38 | FCEUI_Sound(0);\r |
39 | if(ppbufsec)\r |
40 | {\r |
41 | IDirectSoundBuffer_Stop(ppbufsec);\r |
42 | IDirectSoundBuffer_Release(ppbufsec);\r |
43 | ppbufsec=0;\r |
44 | }\r |
45 | if(ppbuf)\r |
46 | {\r |
47 | IDirectSoundBuffer_Stop(ppbuf);\r |
48 | IDirectSoundBuffer_Release(ppbuf);\r |
49 | ppbuf=0;\r |
50 | }\r |
51 | if(ppDS)\r |
52 | {\r |
53 | IDirectSound_Release(ppDS);\r |
54 | ppDS=0;\r |
55 | }\r |
56 | }\r |
57 | \r |
58 | \r |
59 | static VOID *feegle[2];\r |
60 | static DWORD dook[2];\r |
61 | static DWORD writepos=0,playpos=0,lplaypos=0;\r |
62 | void CheckDStatus(void)\r |
63 | {\r |
64 | DWORD status;\r |
65 | status=0;\r |
66 | IDirectSoundBuffer_GetStatus(ppbufw, &status);\r |
67 | \r |
68 | if(status&DSBSTATUS_BUFFERLOST)\r |
69 | {\r |
70 | IDirectSoundBuffer_Restore(ppbufw);\r |
71 | }\r |
72 | \r |
73 | if(!(status&DSBSTATUS_PLAYING))\r |
74 | {\r |
75 | lplaypos=0;\r |
76 | writepos=((soundbufsize)<<bittage);\r |
77 | IDirectSoundBuffer_SetFormat(ppbufw,&wf);\r |
78 | IDirectSoundBuffer_Play(ppbufw,0,0,DSBPLAY_LOOPING);\r |
79 | }\r |
80 | }\r |
81 | \r |
82 | static int16 MBuffer[2048];\r |
83 | void FCEUD_WriteSoundData(int32 *Buffer, int Count)\r |
84 | {\r |
85 | int P;\r |
86 | int k=0;\r |
87 | \r |
88 | if(soundlog)\r |
89 | WriteWaveData(Buffer, Count);\r |
90 | \r |
91 | if(!bittage)\r |
92 | {\r |
93 | for(P=0;P<Count;P++)\r |
94 | *(((uint8*)MBuffer)+P)=((int8)(Buffer[P]>>8))^128;\r |
95 | }\r |
96 | else\r |
97 | {\r |
98 | for(P=0;P<Count;P++)\r |
99 | MBuffer[P]=Buffer[P];\r |
100 | }\r |
101 | ilicpo:\r |
102 | CheckDStatus();\r |
103 | IDirectSoundBuffer_GetCurrentPosition(ppbufw,&playpos,0);\r |
104 | \r |
105 | if(writepos>=DSBufferSize) \r |
106 | if(playpos<lplaypos)\r |
107 | writepos-=DSBufferSize;\r |
108 | lplaypos=playpos;\r |
109 | \r |
110 | /* If the write position is beyond the fill buffer, block. */\r |
111 | if(writepos>=(playpos+(soundbufsize<<bittage)))\r |
112 | //if(!(writepos<playpos+((soundbufsize)<<bittage)))\r |
113 | {\r |
114 | if(!NoWaiting)\r |
115 | {\r |
116 | if(soundsleep==1)\r |
117 | {\r |
118 | if(!k)\r |
119 | {\r |
120 | int stime; \r |
121 | \r |
122 | stime=writepos-(playpos+(soundbufsize<<bittage));\r |
123 | stime*=1000;\r |
124 | stime/=soundrate;\r |
125 | stime>>=1;\r |
126 | if(stime>=5)\r |
127 | Sleep(stime);\r |
128 | k=1;\r |
129 | } \r |
130 | }\r |
131 | else if(soundsleep==2)\r |
132 | {\r |
133 | int stime; \r |
134 | stime=writepos-(playpos+(soundbufsize<<bittage));\r |
135 | stime*=1000;\r |
136 | stime/=soundrate;\r |
137 | stime>>=1;\r |
138 | if(stime>=2)\r |
139 | Sleep(stime);\r |
140 | }\r |
141 | }\r |
142 | BlockingCheck();\r |
143 | if(!soundo || NoWaiting) return;\r |
144 | goto ilicpo;\r |
145 | }\r |
146 | \r |
147 | if(netplaytype && netplayon)\r |
148 | {\r |
149 | if(writepos<=playpos+128)\r |
150 | writepos=playpos+(soundbufsize<<bittage);\r |
151 | }\r |
152 | \r |
153 | {\r |
154 | feegle[0]=feegle[1]=0;\r |
155 | dook[0]=dook[1]=0;\r |
156 | \r |
157 | \r |
158 | ddrval=IDirectSoundBuffer_Lock(ppbufw,(writepos%DSBufferSize),Count<<bittage,&feegle[0],&dook[0],&feegle[1],&dook[1],0);\r |
159 | if(ddrval!=DS_OK)\r |
160 | goto nolock;\r |
161 | \r |
162 | if(feegle[1]!=0 && feegle[1]!=feegle[0])\r |
163 | {\r |
164 | if(soundflush)\r |
165 | {\r |
166 | memset(feegle[0],0x80,dook[0]);\r |
167 | memset(feegle[1],0x80,dook[1]);\r |
168 | }\r |
169 | else\r |
170 | {\r |
171 | memcpy(feegle[0],(uint8 *)MBuffer,dook[0]);\r |
172 | memcpy(feegle[1],((uint8 *)MBuffer)+dook[0],dook[1]);\r |
173 | }\r |
174 | }\r |
175 | else\r |
176 | {\r |
177 | if(soundflush)\r |
178 | memset(feegle[0],0x80,dook[0]);\r |
179 | else\r |
180 | memcpy(feegle[0],(uint8 *)MBuffer,dook[0]);\r |
181 | }\r |
182 | \r |
183 | IDirectSoundBuffer_Unlock(ppbufw,feegle[0],dook[0],feegle[1],dook[1]);\r |
184 | writepos+=Count<<bittage;\r |
185 | }\r |
186 | nolock:\r |
187 | ///////// Ending\r |
188 | }\r |
189 | \r |
190 | int InitSound()\r |
191 | {\r |
192 | DSCAPS dscaps;\r |
193 | DSBCAPS dsbcaps;\r |
194 | \r |
195 | memset(&wf,0x00,sizeof(wf));\r |
196 | wf.wFormatTag = WAVE_FORMAT_PCM;\r |
197 | wf.nChannels = 1;\r |
198 | wf.nSamplesPerSec = soundrate;\r |
199 | \r |
200 | ddrval=DirectSoundCreate(0,&ppDS,0);\r |
201 | if (ddrval != DS_OK)\r |
202 | {\r |
203 | FCEUD_PrintError("DirectSound: Error creating DirectSound object.");\r |
204 | return 0;\r |
205 | }\r |
206 | \r |
207 | if(soundoptions&SO_SECONDARY)\r |
208 | {\r |
209 | trysecondary:\r |
210 | ddrval=IDirectSound_SetCooperativeLevel(ppDS,hAppWnd,DSSCL_PRIORITY);\r |
211 | if (ddrval != DS_OK)\r |
212 | {\r |
213 | FCEUD_PrintError("DirectSound: Error setting cooperative level to DDSCL_PRIORITY.");\r |
214 | TrashSound();\r |
215 | return 0;\r |
216 | }\r |
217 | }\r |
218 | else\r |
219 | {\r |
220 | ddrval=IDirectSound_SetCooperativeLevel(ppDS,hAppWnd,DSSCL_WRITEPRIMARY);\r |
221 | if (ddrval != DS_OK)\r |
222 | {\r |
223 | FCEUD_PrintError("DirectSound: Error setting cooperative level to DDSCL_WRITEPRIMARY. Forcing use of secondary sound buffer and trying again...");\r |
224 | soundoptions|=SO_SECONDARY;\r |
225 | goto trysecondary;\r |
226 | }\r |
227 | }\r |
228 | memset(&dscaps,0x00,sizeof(dscaps));\r |
229 | dscaps.dwSize=sizeof(dscaps);\r |
230 | ddrval=IDirectSound_GetCaps(ppDS,&dscaps);\r |
231 | if(ddrval!=DS_OK)\r |
232 | {\r |
233 | FCEUD_PrintError("DirectSound: Error getting capabilities.");\r |
234 | return 0;\r |
235 | }\r |
236 | \r |
237 | if(dscaps.dwFlags&DSCAPS_EMULDRIVER)\r |
238 | FCEUD_PrintError("DirectSound: Sound device is being emulated through waveform-audio functions. Sound quality will most likely be awful. Try to update your sound device's sound drivers.");\r |
239 | \r |
240 | IDirectSound_Compact(ppDS);\r |
241 | \r |
242 | memset(&DSBufferDesc,0x00,sizeof(DSBUFFERDESC));\r |
243 | DSBufferDesc.dwSize=sizeof(DSBufferDesc);\r |
244 | if(soundoptions&SO_SECONDARY)\r |
245 | DSBufferDesc.dwFlags=DSBCAPS_PRIMARYBUFFER;\r |
246 | else\r |
247 | DSBufferDesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_GETCURRENTPOSITION2;\r |
248 | \r |
249 | ddrval=IDirectSound_CreateSoundBuffer(ppDS,&DSBufferDesc,&ppbuf,0);\r |
250 | if (ddrval != DS_OK)\r |
251 | {\r |
252 | FCEUD_PrintError("DirectSound: Error creating primary buffer.");\r |
253 | TrashSound();\r |
254 | return 0;\r |
255 | } \r |
256 | \r |
257 | memset(&wfa,0x00,sizeof(wfa));\r |
258 | \r |
259 | if(soundoptions&SO_FORCE8BIT)\r |
260 | bittage=0;\r |
261 | else\r |
262 | {\r |
263 | bittage=1;\r |
264 | if( (!(dscaps.dwFlags&DSCAPS_PRIMARY16BIT)) ||\r |
265 | (!(dscaps.dwFlags&DSCAPS_SECONDARY16BIT) && (soundoptions&SO_SECONDARY)))\r |
266 | {\r |
267 | FCEUD_PrintError("DirectSound: 16-bit sound is not supported. Forcing 8-bit sound.");\r |
268 | bittage=0;\r |
269 | soundoptions|=SO_FORCE8BIT;\r |
270 | }\r |
271 | }\r |
272 | \r |
273 | wf.wBitsPerSample=8<<bittage;\r |
274 | wf.nBlockAlign = bittage+1;\r |
275 | wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;\r |
276 | \r |
277 | ddrval=IDirectSoundBuffer_SetFormat(ppbuf,&wf);\r |
278 | if (ddrval != DS_OK)\r |
279 | {\r |
280 | FCEUD_PrintError("DirectSound: Error setting primary buffer format.");\r |
281 | TrashSound();\r |
282 | return 0;\r |
283 | }\r |
284 | \r |
285 | IDirectSoundBuffer_GetFormat(ppbuf,&wfa,sizeof(wfa),0);\r |
286 | \r |
287 | if(soundoptions&SO_SECONDARY)\r |
288 | {\r |
289 | memset(&DSBufferDesc,0x00,sizeof(DSBUFFERDESC)); \r |
290 | DSBufferDesc.dwSize=sizeof(DSBufferDesc);\r |
291 | DSBufferDesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;\r |
292 | if(soundoptions&SO_GFOCUS)\r |
293 | DSBufferDesc.dwFlags|=DSBCAPS_GLOBALFOCUS;\r |
294 | DSBufferDesc.dwBufferBytes=32768;\r |
295 | DSBufferDesc.lpwfxFormat=&wfa; \r |
296 | ddrval=IDirectSound_CreateSoundBuffer(ppDS, &DSBufferDesc, &ppbufsec, 0);\r |
297 | if (ddrval != DS_OK)\r |
298 | {\r |
299 | FCEUD_PrintError("DirectSound: Error creating secondary buffer.");\r |
300 | TrashSound();\r |
301 | return 0;\r |
302 | }\r |
303 | }\r |
304 | \r |
305 | //sprintf(TempArray,"%d\n",wfa.nSamplesPerSec);\r |
306 | //FCEUD_PrintError(TempArray);\r |
307 | \r |
308 | if(soundoptions&SO_SECONDARY)\r |
309 | {\r |
310 | DSBufferSize=32768;\r |
311 | IDirectSoundBuffer_SetCurrentPosition(ppbufsec,0);\r |
312 | ppbufw=ppbufsec;\r |
313 | }\r |
314 | else\r |
315 | {\r |
316 | memset(&dsbcaps,0,sizeof(dsbcaps));\r |
317 | dsbcaps.dwSize=sizeof(dsbcaps);\r |
318 | ddrval=IDirectSoundBuffer_GetCaps(ppbuf,&dsbcaps);\r |
319 | if (ddrval != DS_OK)\r |
320 | {\r |
321 | FCEUD_PrintError("DirectSound: Error getting buffer capabilities.");\r |
322 | TrashSound();\r |
323 | return 0;\r |
324 | }\r |
325 | \r |
326 | DSBufferSize=dsbcaps.dwBufferBytes;\r |
327 | \r |
328 | if(DSBufferSize<8192)\r |
329 | {\r |
330 | FCEUD_PrintError("DirectSound: Primary buffer size is too small!");\r |
331 | TrashSound();\r |
332 | return 0;\r |
333 | }\r |
334 | ppbufw=ppbuf;\r |
335 | }\r |
336 | \r |
337 | soundbufsize=(soundbuftime*soundrate/1000);\r |
338 | FCEUI_Sound(soundrate);\r |
339 | return 1;\r |
340 | }\r |
341 | \r |
342 | BOOL CALLBACK SoundConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r |
343 | {\r |
344 | int x;\r |
345 | \r |
346 | switch(uMsg) {\r |
347 | case WM_INITDIALOG:\r |
348 | if(soundo)\r |
349 | CheckDlgButton(hwndDlg,126,BST_CHECKED);\r |
350 | if(soundoptions&SO_FORCE8BIT)\r |
351 | CheckDlgButton(hwndDlg,122,BST_CHECKED);\r |
352 | if(soundoptions&SO_SECONDARY)\r |
353 | CheckDlgButton(hwndDlg,123,BST_CHECKED);\r |
354 | if(soundoptions&SO_GFOCUS)\r |
355 | CheckDlgButton(hwndDlg,124,BST_CHECKED);\r |
356 | SetDlgItemInt(hwndDlg,200,soundrate,0);\r |
357 | \r |
358 | /* Volume Trackbar */\r |
359 | SendDlgItemMessage(hwndDlg,500,TBM_SETRANGE,1,MAKELONG(0,200));\r |
360 | SendDlgItemMessage(hwndDlg,500,TBM_SETTICFREQ,25,0);\r |
361 | SendDlgItemMessage(hwndDlg,500,TBM_SETPOS,1,200-soundvolume);\r |
362 | \r |
363 | /* buffer size time trackbar */\r |
364 | SendDlgItemMessage(hwndDlg,128,TBM_SETRANGE,1,MAKELONG(15,200));\r |
365 | SendDlgItemMessage(hwndDlg,128,TBM_SETTICFREQ,1,0);\r |
366 | SendDlgItemMessage(hwndDlg,128,TBM_SETPOS,1,soundbuftime);\r |
367 | \r |
368 | {\r |
369 | char tbuf[8];\r |
370 | sprintf(tbuf,"%d",soundbuftime);\r |
371 | SetDlgItemText(hwndDlg,666,(LPTSTR)tbuf);\r |
372 | }\r |
373 | \r |
374 | SendDlgItemMessage(hwndDlg,129,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Mean");\r |
375 | SendDlgItemMessage(hwndDlg,129,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Nice");\r |
376 | SendDlgItemMessage(hwndDlg,129,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Nicest");\r |
377 | SendDlgItemMessage(hwndDlg,129,CB_SETCURSEL,soundsleep,(LPARAM)(LPSTR)0);\r |
378 | break;\r |
379 | case WM_HSCROLL:\r |
380 | // This doesn't seem to work. Hmm...\r |
381 | //if((HWND)lParam==(HWND)128)\r |
382 | {\r |
383 | char tbuf[8];\r |
384 | soundbuftime=SendDlgItemMessage(hwndDlg,128,TBM_GETPOS,0,0);\r |
385 | sprintf(tbuf,"%d",soundbuftime);\r |
386 | SetDlgItemText(hwndDlg,666,(LPTSTR)tbuf);\r |
387 | }\r |
388 | break;\r |
389 | case WM_CLOSE:\r |
390 | case WM_QUIT: goto gornk;\r |
391 | case WM_COMMAND:\r |
392 | if(!(wParam>>16))\r |
393 | switch(wParam&0xFFFF)\r |
394 | {\r |
395 | case 1:\r |
396 | gornk:\r |
397 | soundoptions=0;\r |
398 | if(IsDlgButtonChecked(hwndDlg,122)==BST_CHECKED)\r |
399 | soundoptions|=SO_FORCE8BIT;\r |
400 | if(IsDlgButtonChecked(hwndDlg,123)==BST_CHECKED)\r |
401 | soundoptions|=SO_SECONDARY;\r |
402 | if(IsDlgButtonChecked(hwndDlg,124)==BST_CHECKED)\r |
403 | soundoptions|=SO_GFOCUS;\r |
404 | if(IsDlgButtonChecked(hwndDlg,126)==BST_CHECKED)\r |
405 | soundo=1;\r |
406 | else\r |
407 | soundo=0;\r |
408 | x=GetDlgItemInt(hwndDlg,200,0,0);\r |
409 | if(x<8192 || x>65535)\r |
410 | {\r |
411 | FCEUD_PrintError("Sample rate is out of range(8192-65535).");\r |
412 | break;\r |
413 | }\r |
414 | else\r |
415 | soundrate=x;\r |
416 | \r |
417 | soundvolume=200-SendDlgItemMessage(hwndDlg,500,TBM_GETPOS,0,0);\r |
418 | FCEUI_SetSoundVolume(soundvolume);\r |
419 | soundsleep=SendDlgItemMessage(hwndDlg,129,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r |
420 | EndDialog(hwndDlg,0);\r |
421 | break;\r |
422 | }\r |
423 | }\r |
424 | return 0;\r |
425 | }\r |
426 | \r |
427 | \r |
428 | void ConfigSound(void)\r |
429 | {\r |
430 | int backo=soundo,sr=soundrate;\r |
431 | int so=soundoptions;\r |
432 | \r |
433 | DialogBox(fceu_hInstance,"SOUNDCONFIG",hAppWnd,SoundConCallB);\r |
434 | \r |
435 | if(((backo?1:0)!=(soundo?1:0)))\r |
436 | {\r |
437 | if(!soundo)\r |
438 | TrashSound();\r |
439 | else\r |
440 | soundo=InitSound();\r |
441 | }\r |
442 | else if(( soundoptions!=so || (sr!=soundrate)) && soundo)\r |
443 | {\r |
444 | TrashSound();\r |
445 | soundo=InitSound();\r |
446 | }\r |
447 | soundbufsize=(soundbuftime*soundrate/1000);\r |
448 | }\r |
449 | \r |
450 | \r |
451 | void StopSound(void)\r |
452 | {\r |
453 | if(soundo)\r |
454 | IDirectSoundBuffer_Stop(ppbufw);\r |
455 | }\r |
456 | \r |
457 | #include "wave.c"\r |