ide: Remove duplicated definitions
[qemu/cris-port.git] / audio / winwaveaudio.c
blobf43ae95cf4ec70abfcaf16ab7f537416baa2e26e
1 /* public domain */
3 #include "qemu-common.h"
4 #include "sysemu.h"
5 #include "audio.h"
7 #define AUDIO_CAP "winwave"
8 #include "audio_int.h"
10 #include <windows.h>
11 #include <mmsystem.h>
13 #include "audio_win_int.h"
15 static struct {
16 int dac_headers;
17 int dac_samples;
18 } conf = {
19 .dac_headers = 4,
20 .dac_samples = 1024
23 typedef struct {
24 HWVoiceOut hw;
25 HWAVEOUT hwo;
26 WAVEHDR *hdrs;
27 HANDLE event;
28 void *pcm_buf;
29 int avail;
30 int pending;
31 int curhdr;
32 int paused;
33 CRITICAL_SECTION crit_sect;
34 } WaveVoiceOut;
36 static void winwave_log_mmresult (MMRESULT mr)
38 const char *str = "BUG";
40 switch (mr) {
41 case MMSYSERR_NOERROR:
42 str = "Success";
43 break;
45 case MMSYSERR_INVALHANDLE:
46 str = "Specified device handle is invalid";
47 break;
49 case MMSYSERR_BADDEVICEID:
50 str = "Specified device id is out of range";
51 break;
53 case MMSYSERR_NODRIVER:
54 str = "No device driver is present";
55 break;
57 case MMSYSERR_NOMEM:
58 str = "Unable to allocate or locl memory";
59 break;
61 case WAVERR_SYNC:
62 str = "Device is synchronous but waveOutOpen was called "
63 "without using the WINWAVE_ALLOWSYNC flag";
64 break;
66 case WAVERR_UNPREPARED:
67 str = "The data block pointed to by the pwh parameter "
68 "hasn't been prepared";
69 break;
71 default:
72 AUD_log (AUDIO_CAP, "Reason: Unknown (MMRESULT %#x)\n", mr);
73 return;
76 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
79 static void GCC_FMT_ATTR (2, 3) winwave_logerr (
80 MMRESULT mr,
81 const char *fmt,
82 ...
85 va_list ap;
87 va_start (ap, fmt);
88 AUD_vlog (AUDIO_CAP, fmt, ap);
89 va_end (ap);
91 winwave_log_mmresult (mr);
94 static void winwave_anal_close_out (WaveVoiceOut *wave)
96 MMRESULT mr;
98 mr = waveOutClose (wave->hwo);
99 if (mr != MMSYSERR_NOERROR) {
100 winwave_logerr (mr, "waveOutClose\n");
102 wave->hwo = NULL;
105 static void CALLBACK winwave_callback (
106 HWAVEOUT hwo,
107 UINT msg,
108 DWORD_PTR dwInstance,
109 DWORD_PTR dwParam1,
110 DWORD_PTR dwParam2
113 WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
115 switch (msg) {
116 case WOM_DONE:
118 WAVEHDR *h = (WAVEHDR *) dwParam1;
119 if (!h->dwUser) {
120 h->dwUser = 1;
121 EnterCriticalSection (&wave->crit_sect);
123 wave->avail += conf.dac_samples;
125 LeaveCriticalSection (&wave->crit_sect);
126 if (wave->hw.poll_mode) {
127 if (!SetEvent (wave->event)) {
128 AUD_log (AUDIO_CAP, "SetEvent failed %lx\n",
129 GetLastError ());
134 break;
136 case WOM_CLOSE:
137 case WOM_OPEN:
138 break;
140 default:
141 AUD_log (AUDIO_CAP, "unknown wave callback msg %x\n", msg);
145 static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
147 int i;
148 int err;
149 MMRESULT mr;
150 WAVEFORMATEX wfx;
151 WaveVoiceOut *wave;
153 wave = (WaveVoiceOut *) hw;
155 InitializeCriticalSection (&wave->crit_sect);
157 err = waveformat_from_audio_settings (&wfx, as);
158 if (err) {
159 goto err0;
162 mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
163 (DWORD_PTR) winwave_callback,
164 (DWORD_PTR) wave, CALLBACK_FUNCTION);
165 if (mr != MMSYSERR_NOERROR) {
166 winwave_logerr (mr, "waveOutOpen\n");
167 goto err1;
170 wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
171 sizeof (*wave->hdrs));
172 if (!wave->hdrs) {
173 goto err2;
176 audio_pcm_init_info (&hw->info, as);
177 hw->samples = conf.dac_samples * conf.dac_headers;
178 wave->avail = hw->samples;
180 wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
181 conf.dac_headers << hw->info.shift);
182 if (!wave->pcm_buf) {
183 goto err3;
186 for (i = 0; i < conf.dac_headers; ++i) {
187 WAVEHDR *h = &wave->hdrs[i];
189 h->dwUser = 0;
190 h->dwBufferLength = conf.dac_samples << hw->info.shift;
191 h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
192 h->dwFlags = 0;
194 mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
195 if (mr != MMSYSERR_NOERROR) {
196 winwave_logerr (mr, "waveOutPrepareHeader(%d)\n", wave->curhdr);
197 goto err4;
201 return 0;
203 err4:
204 qemu_free (wave->pcm_buf);
205 err3:
206 qemu_free (wave->hdrs);
207 err2:
208 winwave_anal_close_out (wave);
209 err1:
210 err0:
211 return -1;
214 static int winwave_write (SWVoiceOut *sw, void *buf, int len)
216 return audio_pcm_sw_write (sw, buf, len);
219 static int winwave_run_out (HWVoiceOut *hw, int live)
221 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
222 int decr;
223 int doreset;
225 EnterCriticalSection (&wave->crit_sect);
227 decr = audio_MIN (live, wave->avail);
228 decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
229 wave->pending += decr;
230 wave->avail -= decr;
232 LeaveCriticalSection (&wave->crit_sect);
234 doreset = hw->poll_mode && (wave->pending >= conf.dac_samples);
235 if (doreset && !ResetEvent (wave->event)) {
236 AUD_log (AUDIO_CAP, "ResetEvent failed %lx\n", GetLastError ());
239 while (wave->pending >= conf.dac_samples) {
240 MMRESULT mr;
241 WAVEHDR *h = &wave->hdrs[wave->curhdr];
243 h->dwUser = 0;
244 mr = waveOutWrite (wave->hwo, h, sizeof (*h));
245 if (mr != MMSYSERR_NOERROR) {
246 winwave_logerr (mr, "waveOutWrite(%d)\n", wave->curhdr);
247 break;
250 wave->pending -= conf.dac_samples;
251 wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
254 return decr;
257 static void winwave_poll_out (void *opaque)
259 (void) opaque;
260 audio_run ("winwave_poll_out");
263 static void winwave_fini_out (HWVoiceOut *hw)
265 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
267 winwave_anal_close_out (wave);
269 if (wave->event) {
270 qemu_del_wait_object (wave->event, winwave_poll_out, wave);
271 if (!CloseHandle (wave->event)) {
272 AUD_log (AUDIO_CAP, "CloseHandle failed %lx\n", GetLastError ());
274 wave->event = NULL;
277 qemu_free (wave->pcm_buf);
278 wave->pcm_buf = NULL;
280 qemu_free (wave->hdrs);
281 wave->hdrs = NULL;
284 static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
286 MMRESULT mr;
287 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
289 switch (cmd) {
290 case VOICE_ENABLE:
292 va_list ap;
293 int poll_mode;
295 va_start (ap, cmd);
296 poll_mode = va_arg (ap, int);
297 va_end (ap);
299 if (poll_mode && !wave->event) {
300 wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
301 if (!wave->event) {
302 AUD_log (AUDIO_CAP,
303 "CreateEvent: %lx, poll mode will be disabled\n",
304 GetLastError ());
308 if (wave->event) {
309 int ret;
311 ret = qemu_add_wait_object (wave->event, winwave_poll_out,
312 wave);
313 hw->poll_mode = (ret == 0);
315 else {
316 hw->poll_mode = 0;
318 if (wave->paused) {
319 mr = waveOutRestart (wave->hwo);
320 if (mr != MMSYSERR_NOERROR) {
321 winwave_logerr (mr, "waveOutRestart");
323 wave->paused = 0;
326 return 0;
328 case VOICE_DISABLE:
329 if (!wave->paused) {
330 mr = waveOutPause (wave->hwo);
331 if (mr != MMSYSERR_NOERROR) {
332 winwave_logerr (mr, "waveOutPause");
334 else {
335 wave->paused = 1;
338 if (wave->event) {
339 qemu_del_wait_object (wave->event, winwave_poll_out, wave);
341 return 0;
343 return -1;
346 static void *winwave_audio_init (void)
348 return &conf;
351 static void winwave_audio_fini (void *opaque)
353 (void) opaque;
356 static struct audio_option winwave_options[] = {
358 .name = "DAC_HEADERS",
359 .tag = AUD_OPT_INT,
360 .valp = &conf.dac_headers,
361 .descr = "DAC number of headers",
364 .name = "DAC_SAMPLES",
365 .tag = AUD_OPT_INT,
366 .valp = &conf.dac_samples,
367 .descr = "DAC number of samples per header",
369 { /* End of list */ }
372 static struct audio_pcm_ops winwave_pcm_ops = {
373 .init_out = winwave_init_out,
374 .fini_out = winwave_fini_out,
375 .run_out = winwave_run_out,
376 .write = winwave_write,
377 .ctl_out = winwave_ctl_out
380 struct audio_driver winwave_audio_driver = {
381 .name = "winwave",
382 .descr = "Windows Waveform Audio http://msdn.microsoft.com",
383 .options = winwave_options,
384 .init = winwave_audio_init,
385 .fini = winwave_audio_fini,
386 .pcm_ops = &winwave_pcm_ops,
387 .can_be_default = 1,
388 .max_voices_out = INT_MAX,
389 .max_voices_in = 0,
390 .voice_size_out = sizeof (WaveVoiceOut),
391 .voice_size_in = 0