]> Git Repo - qemu.git/blame - audio/winwaveaudio.c
Windows Waveform Audio driver (no ADC support yet)
[qemu.git] / audio / winwaveaudio.c
CommitLineData
d5631638 1/* public domain */
2
3#include "qemu-common.h"
4#include "audio.h"
5
6#define AUDIO_CAP "winwave"
7#include "audio_int.h"
8
9#include <windows.h>
10#include <mmsystem.h>
11
12#include "audio_win_int.h"
13
14static struct {
15 int dac_headers;
16 int dac_samples;
17} conf = {
18 .dac_headers = 4,
19 .dac_samples = 1024
20};
21
22typedef struct {
23 HWVoiceOut hw;
24 HWAVEOUT hwo;
25 WAVEHDR *hdrs;
26 void *pcm_buf;
27 int avail;
28 int pending;
29 int curhdr;
30 CRITICAL_SECTION crit_sect;
31} WaveVoiceOut;
32
33static void winwave_log_mmresult (MMRESULT mr)
34{
35 const char *str = "BUG";
36
37 switch (mr) {
38 case MMSYSERR_NOERROR:
39 str = "Success";
40 break;
41
42 case MMSYSERR_INVALHANDLE:
43 str = "Specified device handle is invalid";
44 break;
45
46 case MMSYSERR_BADDEVICEID:
47 str = "Specified device id is out of range";
48 break;
49
50 case MMSYSERR_NODRIVER:
51 str = "No device driver is present";
52 break;
53
54 case MMSYSERR_NOMEM:
55 str = "Unable to allocate or locl memory";
56 break;
57
58 case WAVERR_SYNC:
59 str = "Device is synchronous but waveOutOpen was called "
60 "without using the WINWAVE_ALLOWSYNC flag";
61 break;
62
63 case WAVERR_UNPREPARED:
64 str = "The data block pointed to by the pwh parameter "
65 "hasn't been prepared";
66 break;
67
68 default:
69 AUD_log (AUDIO_CAP, "Reason: Unknown (MMRESULT %#x)\n", mr);
70 return;
71 }
72
73 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
74}
75
76static void GCC_FMT_ATTR (2, 3) winwave_logerr (
77 MMRESULT mr,
78 const char *fmt,
79 ...
80 )
81{
82 va_list ap;
83
84 va_start (ap, fmt);
85 AUD_vlog (AUDIO_CAP, fmt, ap);
86 va_end (ap);
87
88 winwave_log_mmresult (mr);
89}
90
91static void winwave_anal_close_out (WaveVoiceOut *wave)
92{
93 MMRESULT mr;
94
95 mr = waveOutClose (wave->hwo);
96 if (mr != MMSYSERR_NOERROR) {
97 winwave_logerr (mr, "waveOutClose\n");
98 }
99 wave->hwo = NULL;
100}
101
102static void CALLBACK winwave_callback (
103 HWAVEOUT hwo,
104 UINT msg,
105 DWORD_PTR dwInstance,
106 DWORD_PTR dwParam1,
107 DWORD_PTR dwParam2
108 )
109{
110 WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
111
112 switch (msg) {
113 case WOM_DONE:
114 {
115 WAVEHDR *h = (WAVEHDR *) dwParam1;
116 if (!h->dwUser) {
117 h->dwUser = 1;
118 EnterCriticalSection (&wave->crit_sect);
119 {
120 wave->avail += conf.dac_samples;
121 }
122 LeaveCriticalSection (&wave->crit_sect);
123 }
124 }
125 break;
126
127 case WOM_CLOSE:
128 case WOM_OPEN:
129 break;
130
131 default:
132 AUD_log (AUDIO_CAP, "unknown wave callback msg %x\n", msg);
133 }
134}
135
136static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
137{
138 int i;
139 int err;
140 MMRESULT mr;
141 WAVEFORMATEX wfx;
142 WaveVoiceOut *wave;
143
144 wave = (WaveVoiceOut *) hw;
145
146 InitializeCriticalSection (&wave->crit_sect);
147
148 err = waveformat_from_audio_settings (&wfx, as);
149 if (err) {
150 goto err0;
151 }
152
153 mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
154 (DWORD_PTR) winwave_callback,
155 (DWORD_PTR) wave, CALLBACK_FUNCTION);
156 if (mr != MMSYSERR_NOERROR) {
157 winwave_logerr (mr, "waveOutOpen\n");
158 goto err1;
159 }
160
161 wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
162 sizeof (*wave->hdrs));
163 if (!wave->hdrs) {
164 goto err2;
165 }
166
167 audio_pcm_init_info (&hw->info, as);
168 hw->samples = conf.dac_samples * conf.dac_headers;
169 wave->avail = hw->samples;
170
171 wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
172 conf.dac_headers << hw->info.shift);
173 if (!wave->pcm_buf) {
174 goto err3;
175 }
176
177 for (i = 0; i < conf.dac_headers; ++i) {
178 WAVEHDR *h = &wave->hdrs[i];
179
180 h->dwUser = 0;
181 h->dwBufferLength = conf.dac_samples << hw->info.shift;
182 h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
183 h->dwFlags = 0;
184
185 mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
186 if (mr != MMSYSERR_NOERROR) {
187 winwave_logerr (mr, "waveOutPrepareHeader(%d)\n", wave->curhdr);
188 goto err4;
189 }
190 }
191
192 return 0;
193
194 err4:
195 qemu_free (wave->pcm_buf);
196 err3:
197 qemu_free (wave->hdrs);
198 err2:
199 winwave_anal_close_out (wave);
200 err1:
201 err0:
202 return -1;
203}
204
205static int winwave_write (SWVoiceOut *sw, void *buf, int len)
206{
207 return audio_pcm_sw_write (sw, buf, len);
208}
209
210static int winwave_run_out (HWVoiceOut *hw, int live)
211{
212 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
213 int decr;
214
215 EnterCriticalSection (&wave->crit_sect);
216 {
217 decr = audio_MIN (live, wave->avail);
218 decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
219 wave->pending += decr;
220 wave->avail -= decr;
221 }
222 LeaveCriticalSection (&wave->crit_sect);
223
224 while (wave->pending >= conf.dac_samples) {
225 MMRESULT mr;
226 WAVEHDR *h = &wave->hdrs[wave->curhdr];
227
228 h->dwUser = 0;
229 mr = waveOutWrite (wave->hwo, h, sizeof (*h));
230 if (mr != MMSYSERR_NOERROR) {
231 winwave_logerr (mr, "waveOutWrite(%d)\n", wave->curhdr);
232 break;
233 }
234
235 wave->pending -= conf.dac_samples;
236 wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
237 }
238 return decr;
239}
240
241static void winwave_fini_out (HWVoiceOut *hw)
242{
243 WaveVoiceOut *wave = (WaveVoiceOut *) hw;
244
245 winwave_anal_close_out (wave);
246
247 qemu_free (wave->pcm_buf);
248 wave->pcm_buf = NULL;
249
250 qemu_free (wave->hdrs);
251 wave->hdrs = NULL;
252}
253
254static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
255{
256 switch (cmd) {
257 case VOICE_ENABLE:
258 return 0;
259
260 case VOICE_DISABLE:
261 return 0;
262 }
263 return -1;
264}
265
266static void *winwave_audio_init (void)
267{
268 return &conf;
269}
270
271static void winwave_audio_fini (void *opaque)
272{
273 (void) opaque;
274}
275
276static struct audio_option winwave_options[] = {
277 {
278 .name = "DAC_HEADERS",
279 .tag = AUD_OPT_INT,
280 .valp = &conf.dac_headers,
281 .descr = "DAC number of headers",
282 },
283 {
284 .name = "DAC_SAMPLES",
285 .tag = AUD_OPT_INT,
286 .valp = &conf.dac_samples,
287 .descr = "DAC number of samples per header",
288 },
289 { /* End of list */ }
290};
291
292static struct audio_pcm_ops winwave_pcm_ops = {
293 .init_out = winwave_init_out,
294 .fini_out = winwave_fini_out,
295 .run_out = winwave_run_out,
296 .write = winwave_write,
297 .ctl_out = winwave_ctl_out
298};
299
300struct audio_driver winwave_audio_driver = {
301 .name = "winwave",
302 .descr = "Windows Waveform Audio http://msdn.microsoft.com",
303 .options = winwave_options,
304 .init = winwave_audio_init,
305 .fini = winwave_audio_fini,
306 .pcm_ops = &winwave_pcm_ops,
307 .can_be_default = 1,
308 .max_voices_out = INT_MAX,
309 .max_voices_in = 0,
310 .voice_size_out = sizeof (WaveVoiceOut),
311 .voice_size_in = 0
312};
This page took 0.053348 seconds and 4 git commands to generate.