gpfce patch
[fceu.git] / drivers / win / sound.c
CommitLineData
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
21FILE *soundlog=0;\r
22void WriteWaveData(int32 *Buffer, int Count);\r
23DWORD WINAPI DSThread(LPVOID lpParam);\r
24LPDIRECTSOUND ppDS=0;\r
25LPDIRECTSOUNDBUFFER ppbuf=0;\r
26LPDIRECTSOUNDBUFFER ppbufsec=0;\r
27LPDIRECTSOUNDBUFFER ppbufw;\r
28\r
29DSBUFFERDESC DSBufferDesc;\r
30WAVEFORMATEX wfa;\r
31WAVEFORMATEX wf;\r
32\r
33static int DSBufferSize=0;\r
34static int bittage;\r
35\r
36void 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
62void 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
82static int16 MBuffer[2048];\r
83void 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
190int 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
342BOOL 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
428void 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
451void StopSound(void)\r
452{\r
453 if(soundo)\r
454 IDirectSoundBuffer_Stop(ppbufw);\r
455}\r
456\r
457#include "wave.c"\r