Statistics
| Branch: | Revision:

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
};