input: add hack to allow abs-only devices
[picodrive.git] / platform / win32 / dsnd.cpp
CommitLineData
823b9004 1//#pragma warning (disable:4201)\r
2#include <stdlib.h>\r
3#define WIN32_LEAN_AND_MEAN\r
4#include <windows.h>\r
5#include <mmsystem.h>\r
6#include <dsound.h>\r
7\r
8#include "dsnd.h"\r
9#include "../common/lprintf.h"\r
10\r
11#define NSEGS 4\r
12#define RELEASE(x) if (x) x->Release(); x=NULL;\r
13\r
14static LPDIRECTSOUND DSound;\r
15static LPDIRECTSOUNDBUFFER LoopBuffer;\r
16static LPDIRECTSOUNDNOTIFY DSoundNotify;\r
17static HANDLE seg_played_event;\r
18static int LoopLen, LoopWrite, LoopSeg; // bytes\r
19\r
20static int LoopBlank(void)\r
21{\r
22 void *mema=NULL,*memb=NULL;\r
23 DWORD sizea=0,sizeb=0;\r
24\r
25 LoopBuffer->Lock(0, LoopLen, &mema,&sizea, &memb,&sizeb, 0);\r
26 \r
27 if (mema) memset(mema,0,sizea);\r
28\r
29 LoopBuffer->Unlock(mema,sizea, memb,sizeb);\r
30\r
31 return 0;\r
32}\r
33\r
34int DSoundInit(HWND wnd_coop, int rate, int stereo, int seg_samples)\r
35{\r
36 DSBUFFERDESC dsbd;\r
37 WAVEFORMATEX wfx;\r
38 DSBPOSITIONNOTIFY notifies[NSEGS];\r
39 int i;\r
40\r
41 memset(&dsbd,0,sizeof(dsbd));\r
42 memset(&wfx,0,sizeof(wfx));\r
43\r
44 // Make wave format:\r
45 wfx.wFormatTag=WAVE_FORMAT_PCM;\r
46 wfx.nChannels=stereo ? 2 : 1;\r
47 wfx.nSamplesPerSec=rate;\r
48 wfx.wBitsPerSample=16;\r
49\r
50 wfx.nBlockAlign=(WORD)((wfx.nChannels*wfx.wBitsPerSample)>>3);\r
51 wfx.nAvgBytesPerSec=wfx.nBlockAlign*wfx.nSamplesPerSec;\r
52\r
53 // Create the DirectSound interface:\r
54 DirectSoundCreate(NULL,&DSound,NULL);\r
55 if (DSound==NULL) return 1;\r
56\r
57 LoopSeg = seg_samples * 2;\r
58 if (stereo)\r
59 LoopSeg *= 2;\r
60\r
61 LoopLen = LoopSeg * NSEGS;\r
62\r
63 DSound->SetCooperativeLevel(wnd_coop, DSSCL_PRIORITY);\r
64 dsbd.dwFlags=DSBCAPS_GLOBALFOCUS; // Play in background\r
65 dsbd.dwFlags|=DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRLPOSITIONNOTIFY;\r
66\r
67 // Create the looping buffer:\r
68 dsbd.dwSize=sizeof(dsbd);\r
69 dsbd.dwBufferBytes=LoopLen;\r
70 dsbd.lpwfxFormat=&wfx;\r
71\r
72 DSound->CreateSoundBuffer(&dsbd,&LoopBuffer,NULL);\r
73 if (LoopBuffer==NULL) return 1;\r
74\r
75 LoopBuffer->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&DSoundNotify);\r
76 if (DSoundNotify == NULL) {\r
77 lprintf("QueryInterface(IID_IDirectSoundNotify) failed\n");\r
78 goto out;\r
79 }\r
80\r
81 seg_played_event = CreateEvent(NULL, 0, 0, NULL);\r
82 if (seg_played_event == NULL)\r
83 goto out;\r
84\r
85 for (i = 0; i < NSEGS; i++) {\r
86 notifies[i].dwOffset = i * LoopSeg;\r
87 notifies[i].hEventNotify = seg_played_event;\r
88 }\r
89 i = DSoundNotify->SetNotificationPositions(NSEGS, notifies);\r
90 if (i != DS_OK) {\r
91 lprintf("SetNotificationPositions failed\n");\r
92 goto out;\r
93 }\r
94\r
95out:\r
96 LoopBlank();\r
97 LoopBuffer->Play(0, 0, DSBPLAY_LOOPING);\r
98 return 0;\r
99}\r
100\r
101void DSoundExit(void)\r
102{\r
103 if (LoopBuffer)\r
104 LoopBuffer->Stop();\r
105 RELEASE(DSoundNotify);\r
106 RELEASE(LoopBuffer)\r
107 RELEASE(DSound)\r
108 CloseHandle(seg_played_event);\r
109 seg_played_event = NULL;\r
110}\r
111\r
112static int WriteSeg(const void *buff)\r
113{\r
114 void *mema=NULL,*memb=NULL;\r
115 DWORD sizea=0,sizeb=0;\r
116 int ret;\r
117\r
118 // Lock the segment at 'LoopWrite' and copy the next segment in\r
119 ret = LoopBuffer->Lock(LoopWrite, LoopSeg, &mema, &sizea, &memb, &sizeb, 0);\r
120 if (ret != DS_OK)\r
121 lprintf("LoopBuffer->Lock() failed: %i\n", ret);\r
122\r
123 if (mema) memcpy(mema,buff,sizea);\r
124// if (memb) memcpy(memb,DSoundNext+sizea,sizeb);\r
125 if (sizeb != 0) lprintf("sizeb is not 0! (%i)\n", sizeb);\r
126\r
127 ret = LoopBuffer->Unlock(mema,sizea, memb, sizeb);\r
128 if (ret != DS_OK)\r
129 lprintf("LoopBuffer->Unlock() failed: %i\n", ret);\r
130\r
131 return 0;\r
132}\r
133\r
134int DSoundUpdate(const void *buff, int blocking)\r
135{\r
136 DWORD play = 0;\r
137 int pos;\r
138\r
139 LoopBuffer->GetCurrentPosition(&play, NULL);\r
140 pos = play;\r
141\r
142 // 'LoopWrite' is the next seg in the loop that we want to write\r
143 // First check that the sound 'play' pointer has moved out of it:\r
144 if (blocking) {\r
145 while (LoopWrite <= pos && pos < LoopWrite + LoopSeg) {\r
146 WaitForSingleObject(seg_played_event, 5000);\r
147 LoopBuffer->GetCurrentPosition(&play, NULL);\r
148 pos = play;\r
149 }\r
150 }\r
151 else {\r
152 if (LoopWrite <= pos && pos < LoopWrite + LoopSeg)\r
153 return 1;\r
154 }\r
155\r
156 WriteSeg(buff);\r
157\r
158 // Advance LoopWrite to next seg:\r
159 LoopWrite += LoopSeg;\r
160 if (LoopWrite + LoopSeg > LoopLen)\r
161 LoopWrite = 0;\r
162\r
163 return 0;\r
164}\r
165\r