root / audio / winwaveaudio.c @ 9c9e7d51
History | View | Annotate | Download (17.5 kB)
1 | d5631638 | malc | /* public domain */
|
---|---|---|---|
2 | d5631638 | malc | |
3 | d5631638 | malc | #include "qemu-common.h" |
4 | e0bda367 | malc | #include "sysemu.h" |
5 | d5631638 | malc | #include "audio.h" |
6 | d5631638 | malc | |
7 | d5631638 | malc | #define AUDIO_CAP "winwave" |
8 | d5631638 | malc | #include "audio_int.h" |
9 | d5631638 | malc | |
10 | d5631638 | malc | #include <windows.h> |
11 | d5631638 | malc | #include <mmsystem.h> |
12 | d5631638 | malc | |
13 | d5631638 | malc | #include "audio_win_int.h" |
14 | d5631638 | malc | |
15 | d5631638 | malc | static struct { |
16 | d5631638 | malc | int dac_headers;
|
17 | d5631638 | malc | int dac_samples;
|
18 | a58c16dc | malc | int adc_headers;
|
19 | a58c16dc | malc | int adc_samples;
|
20 | d5631638 | malc | } conf = { |
21 | d5631638 | malc | .dac_headers = 4,
|
22 | a58c16dc | malc | .dac_samples = 1024,
|
23 | a58c16dc | malc | .adc_headers = 4,
|
24 | a58c16dc | malc | .adc_samples = 1024
|
25 | d5631638 | malc | }; |
26 | d5631638 | malc | |
27 | d5631638 | malc | typedef struct { |
28 | d5631638 | malc | HWVoiceOut hw; |
29 | d5631638 | malc | HWAVEOUT hwo; |
30 | d5631638 | malc | WAVEHDR *hdrs; |
31 | e0bda367 | malc | HANDLE event; |
32 | d5631638 | malc | void *pcm_buf;
|
33 | d5631638 | malc | int avail;
|
34 | d5631638 | malc | int pending;
|
35 | d5631638 | malc | int curhdr;
|
36 | 6165a426 | malc | int paused;
|
37 | d5631638 | malc | CRITICAL_SECTION crit_sect; |
38 | d5631638 | malc | } WaveVoiceOut; |
39 | d5631638 | malc | |
40 | a58c16dc | malc | typedef struct { |
41 | a58c16dc | malc | HWVoiceIn hw; |
42 | a58c16dc | malc | HWAVEIN hwi; |
43 | a58c16dc | malc | WAVEHDR *hdrs; |
44 | a58c16dc | malc | HANDLE event; |
45 | a58c16dc | malc | void *pcm_buf;
|
46 | a58c16dc | malc | int curhdr;
|
47 | a58c16dc | malc | int paused;
|
48 | a58c16dc | malc | int rpos;
|
49 | a58c16dc | malc | int avail;
|
50 | a58c16dc | malc | CRITICAL_SECTION crit_sect; |
51 | a58c16dc | malc | } WaveVoiceIn; |
52 | a58c16dc | malc | |
53 | d5631638 | malc | static void winwave_log_mmresult (MMRESULT mr) |
54 | d5631638 | malc | { |
55 | d5631638 | malc | const char *str = "BUG"; |
56 | d5631638 | malc | |
57 | d5631638 | malc | switch (mr) {
|
58 | d5631638 | malc | case MMSYSERR_NOERROR:
|
59 | d5631638 | malc | str = "Success";
|
60 | d5631638 | malc | break;
|
61 | d5631638 | malc | |
62 | d5631638 | malc | case MMSYSERR_INVALHANDLE:
|
63 | d5631638 | malc | str = "Specified device handle is invalid";
|
64 | d5631638 | malc | break;
|
65 | d5631638 | malc | |
66 | d5631638 | malc | case MMSYSERR_BADDEVICEID:
|
67 | d5631638 | malc | str = "Specified device id is out of range";
|
68 | d5631638 | malc | break;
|
69 | d5631638 | malc | |
70 | d5631638 | malc | case MMSYSERR_NODRIVER:
|
71 | d5631638 | malc | str = "No device driver is present";
|
72 | d5631638 | malc | break;
|
73 | d5631638 | malc | |
74 | d5631638 | malc | case MMSYSERR_NOMEM:
|
75 | d5631638 | malc | str = "Unable to allocate or locl memory";
|
76 | d5631638 | malc | break;
|
77 | d5631638 | malc | |
78 | d5631638 | malc | case WAVERR_SYNC:
|
79 | d5631638 | malc | str = "Device is synchronous but waveOutOpen was called "
|
80 | d5631638 | malc | "without using the WINWAVE_ALLOWSYNC flag";
|
81 | d5631638 | malc | break;
|
82 | d5631638 | malc | |
83 | d5631638 | malc | case WAVERR_UNPREPARED:
|
84 | d5631638 | malc | str = "The data block pointed to by the pwh parameter "
|
85 | d5631638 | malc | "hasn't been prepared";
|
86 | d5631638 | malc | break;
|
87 | d5631638 | malc | |
88 | 2a117d40 | malc | case WAVERR_STILLPLAYING:
|
89 | 2a117d40 | malc | str = "There are still buffers in the queue";
|
90 | 2a117d40 | malc | break;
|
91 | 2a117d40 | malc | |
92 | d5631638 | malc | default:
|
93 | a58c16dc | malc | dolog ("Reason: Unknown (MMRESULT %#x)\n", mr);
|
94 | d5631638 | malc | return;
|
95 | d5631638 | malc | } |
96 | d5631638 | malc | |
97 | a58c16dc | malc | dolog ("Reason: %s\n", str);
|
98 | d5631638 | malc | } |
99 | d5631638 | malc | |
100 | d5631638 | malc | static void GCC_FMT_ATTR (2, 3) winwave_logerr ( |
101 | d5631638 | malc | MMRESULT mr, |
102 | d5631638 | malc | const char *fmt, |
103 | d5631638 | malc | ... |
104 | d5631638 | malc | ) |
105 | d5631638 | malc | { |
106 | d5631638 | malc | va_list ap; |
107 | d5631638 | malc | |
108 | d5631638 | malc | va_start (ap, fmt); |
109 | d5631638 | malc | AUD_vlog (AUDIO_CAP, fmt, ap); |
110 | d5631638 | malc | va_end (ap); |
111 | d5631638 | malc | |
112 | bc578fe0 | malc | AUD_log (NULL, " failed\n"); |
113 | d5631638 | malc | winwave_log_mmresult (mr); |
114 | d5631638 | malc | } |
115 | d5631638 | malc | |
116 | d5631638 | malc | static void winwave_anal_close_out (WaveVoiceOut *wave) |
117 | d5631638 | malc | { |
118 | d5631638 | malc | MMRESULT mr; |
119 | d5631638 | malc | |
120 | d5631638 | malc | mr = waveOutClose (wave->hwo); |
121 | d5631638 | malc | if (mr != MMSYSERR_NOERROR) {
|
122 | bc578fe0 | malc | winwave_logerr (mr, "waveOutClose");
|
123 | d5631638 | malc | } |
124 | d5631638 | malc | wave->hwo = NULL;
|
125 | d5631638 | malc | } |
126 | d5631638 | malc | |
127 | a58c16dc | malc | static void CALLBACK winwave_callback_out ( |
128 | d5631638 | malc | HWAVEOUT hwo, |
129 | d5631638 | malc | UINT msg, |
130 | d5631638 | malc | DWORD_PTR dwInstance, |
131 | d5631638 | malc | DWORD_PTR dwParam1, |
132 | d5631638 | malc | DWORD_PTR dwParam2 |
133 | d5631638 | malc | ) |
134 | d5631638 | malc | { |
135 | d5631638 | malc | WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance; |
136 | d5631638 | malc | |
137 | d5631638 | malc | switch (msg) {
|
138 | d5631638 | malc | case WOM_DONE:
|
139 | d5631638 | malc | { |
140 | d5631638 | malc | WAVEHDR *h = (WAVEHDR *) dwParam1; |
141 | d5631638 | malc | if (!h->dwUser) {
|
142 | d5631638 | malc | h->dwUser = 1;
|
143 | d5631638 | malc | EnterCriticalSection (&wave->crit_sect); |
144 | d5631638 | malc | { |
145 | d5631638 | malc | wave->avail += conf.dac_samples; |
146 | d5631638 | malc | } |
147 | d5631638 | malc | LeaveCriticalSection (&wave->crit_sect); |
148 | e0bda367 | malc | if (wave->hw.poll_mode) {
|
149 | e0bda367 | malc | if (!SetEvent (wave->event)) {
|
150 | a58c16dc | malc | dolog ("DAC SetEvent failed %lx\n", GetLastError ());
|
151 | e0bda367 | malc | } |
152 | e0bda367 | malc | } |
153 | d5631638 | malc | } |
154 | d5631638 | malc | } |
155 | d5631638 | malc | break;
|
156 | d5631638 | malc | |
157 | d5631638 | malc | case WOM_CLOSE:
|
158 | d5631638 | malc | case WOM_OPEN:
|
159 | d5631638 | malc | break;
|
160 | d5631638 | malc | |
161 | d5631638 | malc | default:
|
162 | a58c16dc | malc | dolog ("unknown wave out callback msg %x\n", msg);
|
163 | d5631638 | malc | } |
164 | d5631638 | malc | } |
165 | d5631638 | malc | |
166 | d5631638 | malc | static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as) |
167 | d5631638 | malc | { |
168 | d5631638 | malc | int i;
|
169 | d5631638 | malc | int err;
|
170 | d5631638 | malc | MMRESULT mr; |
171 | d5631638 | malc | WAVEFORMATEX wfx; |
172 | d5631638 | malc | WaveVoiceOut *wave; |
173 | d5631638 | malc | |
174 | d5631638 | malc | wave = (WaveVoiceOut *) hw; |
175 | d5631638 | malc | |
176 | d5631638 | malc | InitializeCriticalSection (&wave->crit_sect); |
177 | d5631638 | malc | |
178 | a58c16dc | malc | err = waveformat_from_audio_settings (&wfx, as); |
179 | d5631638 | malc | if (err) {
|
180 | d5631638 | malc | goto err0;
|
181 | d5631638 | malc | } |
182 | d5631638 | malc | |
183 | d5631638 | malc | mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx, |
184 | a58c16dc | malc | (DWORD_PTR) winwave_callback_out, |
185 | d5631638 | malc | (DWORD_PTR) wave, CALLBACK_FUNCTION); |
186 | d5631638 | malc | if (mr != MMSYSERR_NOERROR) {
|
187 | bc578fe0 | malc | winwave_logerr (mr, "waveOutOpen");
|
188 | d5631638 | malc | goto err1;
|
189 | d5631638 | malc | } |
190 | d5631638 | malc | |
191 | d5631638 | malc | wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers, |
192 | d5631638 | malc | sizeof (*wave->hdrs));
|
193 | d5631638 | malc | if (!wave->hdrs) {
|
194 | d5631638 | malc | goto err2;
|
195 | d5631638 | malc | } |
196 | d5631638 | malc | |
197 | d5631638 | malc | audio_pcm_init_info (&hw->info, as); |
198 | d5631638 | malc | hw->samples = conf.dac_samples * conf.dac_headers; |
199 | d5631638 | malc | wave->avail = hw->samples; |
200 | d5631638 | malc | |
201 | d5631638 | malc | wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples, |
202 | d5631638 | malc | conf.dac_headers << hw->info.shift); |
203 | d5631638 | malc | if (!wave->pcm_buf) {
|
204 | d5631638 | malc | goto err3;
|
205 | d5631638 | malc | } |
206 | d5631638 | malc | |
207 | d5631638 | malc | for (i = 0; i < conf.dac_headers; ++i) { |
208 | d5631638 | malc | WAVEHDR *h = &wave->hdrs[i]; |
209 | d5631638 | malc | |
210 | d5631638 | malc | h->dwUser = 0;
|
211 | d5631638 | malc | h->dwBufferLength = conf.dac_samples << hw->info.shift; |
212 | d5631638 | malc | h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength); |
213 | d5631638 | malc | h->dwFlags = 0;
|
214 | d5631638 | malc | |
215 | d5631638 | malc | mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
|
216 | d5631638 | malc | if (mr != MMSYSERR_NOERROR) {
|
217 | a58c16dc | malc | winwave_logerr (mr, "waveOutPrepareHeader(%d)", i);
|
218 | d5631638 | malc | goto err4;
|
219 | d5631638 | malc | } |
220 | d5631638 | malc | } |
221 | d5631638 | malc | |
222 | d5631638 | malc | return 0; |
223 | d5631638 | malc | |
224 | d5631638 | malc | err4:
|
225 | d5631638 | malc | qemu_free (wave->pcm_buf); |
226 | d5631638 | malc | err3:
|
227 | d5631638 | malc | qemu_free (wave->hdrs); |
228 | d5631638 | malc | err2:
|
229 | d5631638 | malc | winwave_anal_close_out (wave); |
230 | d5631638 | malc | err1:
|
231 | d5631638 | malc | err0:
|
232 | d5631638 | malc | return -1; |
233 | d5631638 | malc | } |
234 | d5631638 | malc | |
235 | d5631638 | malc | static int winwave_write (SWVoiceOut *sw, void *buf, int len) |
236 | d5631638 | malc | { |
237 | d5631638 | malc | return audio_pcm_sw_write (sw, buf, len);
|
238 | d5631638 | malc | } |
239 | d5631638 | malc | |
240 | d5631638 | malc | static int winwave_run_out (HWVoiceOut *hw, int live) |
241 | d5631638 | malc | { |
242 | d5631638 | malc | WaveVoiceOut *wave = (WaveVoiceOut *) hw; |
243 | d5631638 | malc | int decr;
|
244 | e0bda367 | malc | int doreset;
|
245 | d5631638 | malc | |
246 | d5631638 | malc | EnterCriticalSection (&wave->crit_sect); |
247 | d5631638 | malc | { |
248 | d5631638 | malc | decr = audio_MIN (live, wave->avail); |
249 | d5631638 | malc | decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending); |
250 | d5631638 | malc | wave->pending += decr; |
251 | d5631638 | malc | wave->avail -= decr; |
252 | d5631638 | malc | } |
253 | d5631638 | malc | LeaveCriticalSection (&wave->crit_sect); |
254 | d5631638 | malc | |
255 | e0bda367 | malc | doreset = hw->poll_mode && (wave->pending >= conf.dac_samples); |
256 | e0bda367 | malc | if (doreset && !ResetEvent (wave->event)) {
|
257 | a58c16dc | malc | dolog ("DAC ResetEvent failed %lx\n", GetLastError ());
|
258 | e0bda367 | malc | } |
259 | e0bda367 | malc | |
260 | d5631638 | malc | while (wave->pending >= conf.dac_samples) {
|
261 | d5631638 | malc | MMRESULT mr; |
262 | d5631638 | malc | WAVEHDR *h = &wave->hdrs[wave->curhdr]; |
263 | d5631638 | malc | |
264 | d5631638 | malc | h->dwUser = 0;
|
265 | d5631638 | malc | mr = waveOutWrite (wave->hwo, h, sizeof (*h));
|
266 | d5631638 | malc | if (mr != MMSYSERR_NOERROR) {
|
267 | bc578fe0 | malc | winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
|
268 | d5631638 | malc | break;
|
269 | d5631638 | malc | } |
270 | d5631638 | malc | |
271 | d5631638 | malc | wave->pending -= conf.dac_samples; |
272 | d5631638 | malc | wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
|
273 | d5631638 | malc | } |
274 | e0bda367 | malc | |
275 | d5631638 | malc | return decr;
|
276 | d5631638 | malc | } |
277 | d5631638 | malc | |
278 | a58c16dc | malc | static void winwave_poll (void *opaque) |
279 | f4e8d0b7 | malc | { |
280 | f4e8d0b7 | malc | (void) opaque;
|
281 | a58c16dc | malc | audio_run ("winwave_poll");
|
282 | f4e8d0b7 | malc | } |
283 | f4e8d0b7 | malc | |
284 | d5631638 | malc | static void winwave_fini_out (HWVoiceOut *hw) |
285 | d5631638 | malc | { |
286 | 2a117d40 | malc | int i;
|
287 | 2a117d40 | malc | MMRESULT mr; |
288 | d5631638 | malc | WaveVoiceOut *wave = (WaveVoiceOut *) hw; |
289 | d5631638 | malc | |
290 | 2a117d40 | malc | mr = waveOutReset (wave->hwo); |
291 | 2a117d40 | malc | if (mr != MMSYSERR_NOERROR) {
|
292 | bc578fe0 | malc | winwave_logerr (mr, "waveOutReset");
|
293 | 2a117d40 | malc | } |
294 | 2a117d40 | malc | |
295 | 2a117d40 | malc | for (i = 0; i < conf.dac_headers; ++i) { |
296 | 2a117d40 | malc | mr = waveOutUnprepareHeader (wave->hwo, &wave->hdrs[i], |
297 | 2a117d40 | malc | sizeof (wave->hdrs[i]));
|
298 | 2a117d40 | malc | if (mr != MMSYSERR_NOERROR) {
|
299 | bc578fe0 | malc | winwave_logerr (mr, "waveOutUnprepareHeader(%d)", i);
|
300 | 2a117d40 | malc | } |
301 | 2a117d40 | malc | } |
302 | 2a117d40 | malc | |
303 | 875ef647 | malc | winwave_anal_close_out (wave); |
304 | 875ef647 | malc | |
305 | e0bda367 | malc | if (wave->event) {
|
306 | a58c16dc | malc | qemu_del_wait_object (wave->event, winwave_poll, wave); |
307 | e0bda367 | malc | if (!CloseHandle (wave->event)) {
|
308 | a58c16dc | malc | dolog ("DAC CloseHandle failed %lx\n", GetLastError ());
|
309 | e0bda367 | malc | } |
310 | e0bda367 | malc | wave->event = NULL;
|
311 | e0bda367 | malc | } |
312 | e0bda367 | malc | |
313 | f4e8d0b7 | malc | qemu_free (wave->pcm_buf); |
314 | f4e8d0b7 | malc | wave->pcm_buf = NULL;
|
315 | f4e8d0b7 | malc | |
316 | f4e8d0b7 | malc | qemu_free (wave->hdrs); |
317 | f4e8d0b7 | malc | wave->hdrs = NULL;
|
318 | d5631638 | malc | } |
319 | d5631638 | malc | |
320 | d5631638 | malc | static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...) |
321 | d5631638 | malc | { |
322 | 6165a426 | malc | MMRESULT mr; |
323 | e0bda367 | malc | WaveVoiceOut *wave = (WaveVoiceOut *) hw; |
324 | e0bda367 | malc | |
325 | d5631638 | malc | switch (cmd) {
|
326 | d5631638 | malc | case VOICE_ENABLE:
|
327 | e0bda367 | malc | { |
328 | e0bda367 | malc | va_list ap; |
329 | e0bda367 | malc | int poll_mode;
|
330 | e0bda367 | malc | |
331 | e0bda367 | malc | va_start (ap, cmd); |
332 | e0bda367 | malc | poll_mode = va_arg (ap, int);
|
333 | e0bda367 | malc | va_end (ap); |
334 | e0bda367 | malc | |
335 | e0bda367 | malc | if (poll_mode && !wave->event) {
|
336 | e0bda367 | malc | wave->event = CreateEvent (NULL, TRUE, TRUE, NULL); |
337 | e0bda367 | malc | if (!wave->event) {
|
338 | a58c16dc | malc | dolog ("DAC CreateEvent: %lx, poll mode will be disabled\n",
|
339 | a58c16dc | malc | GetLastError ()); |
340 | e0bda367 | malc | } |
341 | e0bda367 | malc | } |
342 | e0bda367 | malc | |
343 | e0bda367 | malc | if (wave->event) {
|
344 | e0bda367 | malc | int ret;
|
345 | e0bda367 | malc | |
346 | a58c16dc | malc | ret = qemu_add_wait_object (wave->event, winwave_poll, wave); |
347 | e0bda367 | malc | hw->poll_mode = (ret == 0);
|
348 | e0bda367 | malc | } |
349 | e0bda367 | malc | else {
|
350 | e0bda367 | malc | hw->poll_mode = 0;
|
351 | e0bda367 | malc | } |
352 | 6165a426 | malc | if (wave->paused) {
|
353 | 6165a426 | malc | mr = waveOutRestart (wave->hwo); |
354 | 6165a426 | malc | if (mr != MMSYSERR_NOERROR) {
|
355 | 6165a426 | malc | winwave_logerr (mr, "waveOutRestart");
|
356 | 6165a426 | malc | } |
357 | 6165a426 | malc | wave->paused = 0;
|
358 | 6165a426 | malc | } |
359 | e0bda367 | malc | } |
360 | d5631638 | malc | return 0; |
361 | d5631638 | malc | |
362 | d5631638 | malc | case VOICE_DISABLE:
|
363 | 6165a426 | malc | if (!wave->paused) {
|
364 | 6165a426 | malc | mr = waveOutPause (wave->hwo); |
365 | 6165a426 | malc | if (mr != MMSYSERR_NOERROR) {
|
366 | 6165a426 | malc | winwave_logerr (mr, "waveOutPause");
|
367 | 6165a426 | malc | } |
368 | 6165a426 | malc | else {
|
369 | 6165a426 | malc | wave->paused = 1;
|
370 | 6165a426 | malc | } |
371 | 6165a426 | malc | } |
372 | e0bda367 | malc | if (wave->event) {
|
373 | a58c16dc | malc | qemu_del_wait_object (wave->event, winwave_poll, wave); |
374 | e0bda367 | malc | } |
375 | d5631638 | malc | return 0; |
376 | d5631638 | malc | } |
377 | d5631638 | malc | return -1; |
378 | d5631638 | malc | } |
379 | d5631638 | malc | |
380 | a58c16dc | malc | static void winwave_anal_close_in (WaveVoiceIn *wave) |
381 | a58c16dc | malc | { |
382 | a58c16dc | malc | MMRESULT mr; |
383 | a58c16dc | malc | |
384 | a58c16dc | malc | mr = waveInClose (wave->hwi); |
385 | a58c16dc | malc | if (mr != MMSYSERR_NOERROR) {
|
386 | a58c16dc | malc | winwave_logerr (mr, "waveInClose");
|
387 | a58c16dc | malc | } |
388 | a58c16dc | malc | wave->hwi = NULL;
|
389 | a58c16dc | malc | } |
390 | a58c16dc | malc | |
391 | a58c16dc | malc | static void CALLBACK winwave_callback_in ( |
392 | a58c16dc | malc | HWAVEIN *hwi, |
393 | a58c16dc | malc | UINT msg, |
394 | a58c16dc | malc | DWORD_PTR dwInstance, |
395 | a58c16dc | malc | DWORD_PTR dwParam1, |
396 | a58c16dc | malc | DWORD_PTR dwParam2 |
397 | a58c16dc | malc | ) |
398 | a58c16dc | malc | { |
399 | a58c16dc | malc | WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance; |
400 | a58c16dc | malc | |
401 | a58c16dc | malc | switch (msg) {
|
402 | a58c16dc | malc | case WIM_DATA:
|
403 | a58c16dc | malc | { |
404 | a58c16dc | malc | WAVEHDR *h = (WAVEHDR *) dwParam1; |
405 | a58c16dc | malc | if (!h->dwUser) {
|
406 | a58c16dc | malc | h->dwUser = 1;
|
407 | a58c16dc | malc | EnterCriticalSection (&wave->crit_sect); |
408 | a58c16dc | malc | { |
409 | a58c16dc | malc | wave->avail += conf.adc_samples; |
410 | a58c16dc | malc | } |
411 | a58c16dc | malc | LeaveCriticalSection (&wave->crit_sect); |
412 | a58c16dc | malc | if (wave->hw.poll_mode) {
|
413 | a58c16dc | malc | if (!SetEvent (wave->event)) {
|
414 | a58c16dc | malc | dolog ("ADC SetEvent failed %lx\n", GetLastError ());
|
415 | a58c16dc | malc | } |
416 | a58c16dc | malc | } |
417 | a58c16dc | malc | } |
418 | a58c16dc | malc | } |
419 | a58c16dc | malc | break;
|
420 | a58c16dc | malc | |
421 | a58c16dc | malc | case WIM_CLOSE:
|
422 | a58c16dc | malc | case WIM_OPEN:
|
423 | a58c16dc | malc | break;
|
424 | a58c16dc | malc | |
425 | a58c16dc | malc | default:
|
426 | a58c16dc | malc | dolog ("unknown wave in callback msg %x\n", msg);
|
427 | a58c16dc | malc | } |
428 | a58c16dc | malc | } |
429 | a58c16dc | malc | |
430 | a58c16dc | malc | static void winwave_add_buffers (WaveVoiceIn *wave, int samples) |
431 | a58c16dc | malc | { |
432 | a58c16dc | malc | int doreset;
|
433 | a58c16dc | malc | |
434 | a58c16dc | malc | doreset = wave->hw.poll_mode && (samples >= conf.adc_samples); |
435 | a58c16dc | malc | if (doreset && !ResetEvent (wave->event)) {
|
436 | a58c16dc | malc | dolog ("ADC ResetEvent failed %lx\n", GetLastError ());
|
437 | a58c16dc | malc | } |
438 | a58c16dc | malc | |
439 | a58c16dc | malc | while (samples >= conf.adc_samples) {
|
440 | a58c16dc | malc | MMRESULT mr; |
441 | a58c16dc | malc | WAVEHDR *h = &wave->hdrs[wave->curhdr]; |
442 | a58c16dc | malc | |
443 | a58c16dc | malc | h->dwUser = 0;
|
444 | a58c16dc | malc | mr = waveInAddBuffer (wave->hwi, h, sizeof (*h));
|
445 | a58c16dc | malc | if (mr != MMSYSERR_NOERROR) {
|
446 | a58c16dc | malc | winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr);
|
447 | a58c16dc | malc | } |
448 | a58c16dc | malc | wave->curhdr = (wave->curhdr + 1) % conf.adc_headers;
|
449 | a58c16dc | malc | samples -= conf.adc_samples; |
450 | a58c16dc | malc | } |
451 | a58c16dc | malc | } |
452 | a58c16dc | malc | |
453 | a58c16dc | malc | static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as) |
454 | a58c16dc | malc | { |
455 | a58c16dc | malc | int i;
|
456 | a58c16dc | malc | int err;
|
457 | a58c16dc | malc | MMRESULT mr; |
458 | a58c16dc | malc | WAVEFORMATEX wfx; |
459 | a58c16dc | malc | WaveVoiceIn *wave; |
460 | a58c16dc | malc | |
461 | a58c16dc | malc | wave = (WaveVoiceIn *) hw; |
462 | a58c16dc | malc | |
463 | a58c16dc | malc | InitializeCriticalSection (&wave->crit_sect); |
464 | a58c16dc | malc | |
465 | a58c16dc | malc | err = waveformat_from_audio_settings (&wfx, as); |
466 | a58c16dc | malc | if (err) {
|
467 | a58c16dc | malc | goto err0;
|
468 | a58c16dc | malc | } |
469 | a58c16dc | malc | |
470 | a58c16dc | malc | mr = waveInOpen (&wave->hwi, WAVE_MAPPER, &wfx, |
471 | a58c16dc | malc | (DWORD_PTR) winwave_callback_in, |
472 | a58c16dc | malc | (DWORD_PTR) wave, CALLBACK_FUNCTION); |
473 | a58c16dc | malc | if (mr != MMSYSERR_NOERROR) {
|
474 | a58c16dc | malc | winwave_logerr (mr, "waveInOpen");
|
475 | a58c16dc | malc | goto err1;
|
476 | a58c16dc | malc | } |
477 | a58c16dc | malc | |
478 | a58c16dc | malc | wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers, |
479 | a58c16dc | malc | sizeof (*wave->hdrs));
|
480 | a58c16dc | malc | if (!wave->hdrs) {
|
481 | a58c16dc | malc | goto err2;
|
482 | a58c16dc | malc | } |
483 | a58c16dc | malc | |
484 | a58c16dc | malc | audio_pcm_init_info (&hw->info, as); |
485 | a58c16dc | malc | hw->samples = conf.adc_samples * conf.adc_headers; |
486 | a58c16dc | malc | wave->avail = 0;
|
487 | a58c16dc | malc | |
488 | a58c16dc | malc | wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.adc_samples, |
489 | a58c16dc | malc | conf.adc_headers << hw->info.shift); |
490 | a58c16dc | malc | if (!wave->pcm_buf) {
|
491 | a58c16dc | malc | goto err3;
|
492 | a58c16dc | malc | } |
493 | a58c16dc | malc | |
494 | a58c16dc | malc | for (i = 0; i < conf.adc_headers; ++i) { |
495 | a58c16dc | malc | WAVEHDR *h = &wave->hdrs[i]; |
496 | a58c16dc | malc | |
497 | a58c16dc | malc | h->dwUser = 0;
|
498 | a58c16dc | malc | h->dwBufferLength = conf.adc_samples << hw->info.shift; |
499 | a58c16dc | malc | h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength); |
500 | a58c16dc | malc | h->dwFlags = 0;
|
501 | a58c16dc | malc | |
502 | a58c16dc | malc | mr = waveInPrepareHeader (wave->hwi, h, sizeof (*h));
|
503 | a58c16dc | malc | if (mr != MMSYSERR_NOERROR) {
|
504 | a58c16dc | malc | winwave_logerr (mr, "waveInPrepareHeader(%d)", i);
|
505 | a58c16dc | malc | goto err4;
|
506 | a58c16dc | malc | } |
507 | a58c16dc | malc | } |
508 | a58c16dc | malc | |
509 | a58c16dc | malc | wave->paused = 1;
|
510 | a58c16dc | malc | winwave_add_buffers (wave, hw->samples); |
511 | a58c16dc | malc | return 0; |
512 | a58c16dc | malc | |
513 | a58c16dc | malc | err4:
|
514 | a58c16dc | malc | qemu_free (wave->pcm_buf); |
515 | a58c16dc | malc | err3:
|
516 | a58c16dc | malc | qemu_free (wave->hdrs); |
517 | a58c16dc | malc | err2:
|
518 | a58c16dc | malc | winwave_anal_close_in (wave); |
519 | a58c16dc | malc | err1:
|
520 | a58c16dc | malc | err0:
|
521 | a58c16dc | malc | return -1; |
522 | a58c16dc | malc | } |
523 | a58c16dc | malc | |
524 | a58c16dc | malc | static void winwave_fini_in (HWVoiceIn *hw) |
525 | a58c16dc | malc | { |
526 | a58c16dc | malc | int i;
|
527 | a58c16dc | malc | MMRESULT mr; |
528 | a58c16dc | malc | WaveVoiceIn *wave = (WaveVoiceIn *) hw; |
529 | a58c16dc | malc | |
530 | a58c16dc | malc | mr = waveInReset (wave->hwi); |
531 | a58c16dc | malc | if (mr != MMSYSERR_NOERROR) {
|
532 | a58c16dc | malc | winwave_logerr (mr, "waveInReset");
|
533 | a58c16dc | malc | } |
534 | a58c16dc | malc | |
535 | a58c16dc | malc | for (i = 0; i < conf.adc_headers; ++i) { |
536 | a58c16dc | malc | mr = waveInUnprepareHeader (wave->hwi, &wave->hdrs[i], |
537 | a58c16dc | malc | sizeof (wave->hdrs[i]));
|
538 | a58c16dc | malc | if (mr != MMSYSERR_NOERROR) {
|
539 | a58c16dc | malc | winwave_logerr (mr, "waveInUnprepareHeader(%d)", i);
|
540 | a58c16dc | malc | } |
541 | a58c16dc | malc | } |
542 | a58c16dc | malc | |
543 | a58c16dc | malc | winwave_anal_close_in (wave); |
544 | a58c16dc | malc | |
545 | a58c16dc | malc | if (wave->event) {
|
546 | a58c16dc | malc | qemu_del_wait_object (wave->event, winwave_poll, wave); |
547 | a58c16dc | malc | if (!CloseHandle (wave->event)) {
|
548 | a58c16dc | malc | dolog ("ADC CloseHandle failed %lx\n", GetLastError ());
|
549 | a58c16dc | malc | } |
550 | a58c16dc | malc | wave->event = NULL;
|
551 | a58c16dc | malc | } |
552 | a58c16dc | malc | |
553 | a58c16dc | malc | qemu_free (wave->pcm_buf); |
554 | a58c16dc | malc | wave->pcm_buf = NULL;
|
555 | a58c16dc | malc | |
556 | a58c16dc | malc | qemu_free (wave->hdrs); |
557 | a58c16dc | malc | wave->hdrs = NULL;
|
558 | a58c16dc | malc | } |
559 | a58c16dc | malc | |
560 | a58c16dc | malc | static int winwave_run_in (HWVoiceIn *hw) |
561 | a58c16dc | malc | { |
562 | a58c16dc | malc | WaveVoiceIn *wave = (WaveVoiceIn *) hw; |
563 | a58c16dc | malc | int live = audio_pcm_hw_get_live_in (hw);
|
564 | a58c16dc | malc | int dead = hw->samples - live;
|
565 | a58c16dc | malc | int decr, ret;
|
566 | a58c16dc | malc | |
567 | a58c16dc | malc | if (!dead) {
|
568 | a58c16dc | malc | return 0; |
569 | a58c16dc | malc | } |
570 | a58c16dc | malc | |
571 | a58c16dc | malc | EnterCriticalSection (&wave->crit_sect); |
572 | a58c16dc | malc | { |
573 | a58c16dc | malc | decr = audio_MIN (dead, wave->avail); |
574 | a58c16dc | malc | wave->avail -= decr; |
575 | a58c16dc | malc | } |
576 | a58c16dc | malc | LeaveCriticalSection (&wave->crit_sect); |
577 | a58c16dc | malc | |
578 | a58c16dc | malc | ret = decr; |
579 | a58c16dc | malc | while (decr) {
|
580 | a58c16dc | malc | int left = hw->samples - hw->wpos;
|
581 | a58c16dc | malc | int conv = audio_MIN (left, decr);
|
582 | a58c16dc | malc | hw->conv (hw->conv_buf + hw->wpos, |
583 | a58c16dc | malc | advance (wave->pcm_buf, wave->rpos << hw->info.shift), |
584 | a58c16dc | malc | conv, |
585 | a58c16dc | malc | &nominal_volume); |
586 | a58c16dc | malc | |
587 | a58c16dc | malc | wave->rpos = (wave->rpos + conv) % hw->samples; |
588 | a58c16dc | malc | hw->wpos = (hw->wpos + conv) % hw->samples; |
589 | a58c16dc | malc | decr -= conv; |
590 | a58c16dc | malc | } |
591 | a58c16dc | malc | |
592 | a58c16dc | malc | winwave_add_buffers (wave, ret); |
593 | a58c16dc | malc | return ret;
|
594 | a58c16dc | malc | } |
595 | a58c16dc | malc | |
596 | a58c16dc | malc | static int winwave_read (SWVoiceIn *sw, void *buf, int size) |
597 | a58c16dc | malc | { |
598 | a58c16dc | malc | return audio_pcm_sw_read (sw, buf, size);
|
599 | a58c16dc | malc | } |
600 | a58c16dc | malc | |
601 | a58c16dc | malc | static int winwave_ctl_in (HWVoiceIn *hw, int cmd, ...) |
602 | a58c16dc | malc | { |
603 | a58c16dc | malc | MMRESULT mr; |
604 | a58c16dc | malc | WaveVoiceIn *wave = (WaveVoiceIn *) hw; |
605 | a58c16dc | malc | |
606 | a58c16dc | malc | switch (cmd) {
|
607 | a58c16dc | malc | case VOICE_ENABLE:
|
608 | a58c16dc | malc | { |
609 | a58c16dc | malc | va_list ap; |
610 | a58c16dc | malc | int poll_mode;
|
611 | a58c16dc | malc | |
612 | a58c16dc | malc | va_start (ap, cmd); |
613 | a58c16dc | malc | poll_mode = va_arg (ap, int);
|
614 | a58c16dc | malc | va_end (ap); |
615 | a58c16dc | malc | |
616 | a58c16dc | malc | if (poll_mode && !wave->event) {
|
617 | a58c16dc | malc | wave->event = CreateEvent (NULL, TRUE, TRUE, NULL); |
618 | a58c16dc | malc | if (!wave->event) {
|
619 | a58c16dc | malc | dolog ("ADC CreateEvent: %lx, poll mode will be disabled\n",
|
620 | a58c16dc | malc | GetLastError ()); |
621 | a58c16dc | malc | } |
622 | a58c16dc | malc | } |
623 | a58c16dc | malc | |
624 | a58c16dc | malc | if (wave->event) {
|
625 | a58c16dc | malc | int ret;
|
626 | a58c16dc | malc | |
627 | a58c16dc | malc | ret = qemu_add_wait_object (wave->event, winwave_poll, wave); |
628 | a58c16dc | malc | hw->poll_mode = (ret == 0);
|
629 | a58c16dc | malc | } |
630 | a58c16dc | malc | else {
|
631 | a58c16dc | malc | hw->poll_mode = 0;
|
632 | a58c16dc | malc | } |
633 | a58c16dc | malc | if (wave->paused) {
|
634 | a58c16dc | malc | mr = waveInStart (wave->hwi); |
635 | a58c16dc | malc | if (mr != MMSYSERR_NOERROR) {
|
636 | a58c16dc | malc | winwave_logerr (mr, "waveInStart");
|
637 | a58c16dc | malc | } |
638 | a58c16dc | malc | wave->paused = 0;
|
639 | a58c16dc | malc | } |
640 | a58c16dc | malc | } |
641 | a58c16dc | malc | return 0; |
642 | a58c16dc | malc | |
643 | a58c16dc | malc | case VOICE_DISABLE:
|
644 | a58c16dc | malc | if (!wave->paused) {
|
645 | a58c16dc | malc | mr = waveInStop (wave->hwi); |
646 | a58c16dc | malc | if (mr != MMSYSERR_NOERROR) {
|
647 | a58c16dc | malc | winwave_logerr (mr, "waveInStop");
|
648 | a58c16dc | malc | } |
649 | a58c16dc | malc | else {
|
650 | a58c16dc | malc | wave->paused = 1;
|
651 | a58c16dc | malc | } |
652 | a58c16dc | malc | } |
653 | a58c16dc | malc | if (wave->event) {
|
654 | a58c16dc | malc | qemu_del_wait_object (wave->event, winwave_poll, wave); |
655 | a58c16dc | malc | } |
656 | a58c16dc | malc | return 0; |
657 | a58c16dc | malc | } |
658 | a58c16dc | malc | return 0; |
659 | a58c16dc | malc | } |
660 | a58c16dc | malc | |
661 | d5631638 | malc | static void *winwave_audio_init (void) |
662 | d5631638 | malc | { |
663 | d5631638 | malc | return &conf;
|
664 | d5631638 | malc | } |
665 | d5631638 | malc | |
666 | d5631638 | malc | static void winwave_audio_fini (void *opaque) |
667 | d5631638 | malc | { |
668 | d5631638 | malc | (void) opaque;
|
669 | d5631638 | malc | } |
670 | d5631638 | malc | |
671 | d5631638 | malc | static struct audio_option winwave_options[] = { |
672 | d5631638 | malc | { |
673 | d5631638 | malc | .name = "DAC_HEADERS",
|
674 | d5631638 | malc | .tag = AUD_OPT_INT, |
675 | d5631638 | malc | .valp = &conf.dac_headers, |
676 | d5631638 | malc | .descr = "DAC number of headers",
|
677 | d5631638 | malc | }, |
678 | d5631638 | malc | { |
679 | d5631638 | malc | .name = "DAC_SAMPLES",
|
680 | d5631638 | malc | .tag = AUD_OPT_INT, |
681 | d5631638 | malc | .valp = &conf.dac_samples, |
682 | d5631638 | malc | .descr = "DAC number of samples per header",
|
683 | d5631638 | malc | }, |
684 | a58c16dc | malc | { |
685 | a58c16dc | malc | .name = "ADC_HEADERS",
|
686 | a58c16dc | malc | .tag = AUD_OPT_INT, |
687 | a58c16dc | malc | .valp = &conf.adc_headers, |
688 | a58c16dc | malc | .descr = "ADC number of headers",
|
689 | a58c16dc | malc | }, |
690 | a58c16dc | malc | { |
691 | a58c16dc | malc | .name = "ADC_SAMPLES",
|
692 | a58c16dc | malc | .tag = AUD_OPT_INT, |
693 | a58c16dc | malc | .valp = &conf.adc_samples, |
694 | a58c16dc | malc | .descr = "ADC number of samples per header",
|
695 | a58c16dc | malc | }, |
696 | d5631638 | malc | { /* End of list */ }
|
697 | d5631638 | malc | }; |
698 | d5631638 | malc | |
699 | d5631638 | malc | static struct audio_pcm_ops winwave_pcm_ops = { |
700 | d5631638 | malc | .init_out = winwave_init_out, |
701 | d5631638 | malc | .fini_out = winwave_fini_out, |
702 | d5631638 | malc | .run_out = winwave_run_out, |
703 | d5631638 | malc | .write = winwave_write, |
704 | a58c16dc | malc | .ctl_out = winwave_ctl_out, |
705 | a58c16dc | malc | .init_in = winwave_init_in, |
706 | a58c16dc | malc | .fini_in = winwave_fini_in, |
707 | a58c16dc | malc | .run_in = winwave_run_in, |
708 | a58c16dc | malc | .read = winwave_read, |
709 | a58c16dc | malc | .ctl_in = winwave_ctl_in |
710 | d5631638 | malc | }; |
711 | d5631638 | malc | |
712 | d5631638 | malc | struct audio_driver winwave_audio_driver = {
|
713 | d5631638 | malc | .name = "winwave",
|
714 | d5631638 | malc | .descr = "Windows Waveform Audio http://msdn.microsoft.com",
|
715 | d5631638 | malc | .options = winwave_options, |
716 | d5631638 | malc | .init = winwave_audio_init, |
717 | d5631638 | malc | .fini = winwave_audio_fini, |
718 | d5631638 | malc | .pcm_ops = &winwave_pcm_ops, |
719 | d5631638 | malc | .can_be_default = 1,
|
720 | d5631638 | malc | .max_voices_out = INT_MAX, |
721 | a58c16dc | malc | .max_voices_in = INT_MAX, |
722 | d5631638 | malc | .voice_size_out = sizeof (WaveVoiceOut),
|
723 | a58c16dc | malc | .voice_size_in = sizeof (WaveVoiceIn)
|
724 | d5631638 | malc | }; |