root / audio / audio.c @ afc7df11
History | View | Annotate | Download (21 kB)
1 | 85571bc7 | bellard | /*
|
---|---|---|---|
2 | 85571bc7 | bellard | * QEMU Audio subsystem
|
3 | 85571bc7 | bellard | *
|
4 | 85571bc7 | bellard | * Copyright (c) 2003-2004 Vassili Karpov (malc)
|
5 | 85571bc7 | bellard | *
|
6 | 85571bc7 | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 85571bc7 | bellard | * of this software and associated documentation files (the "Software"), to deal
|
8 | 85571bc7 | bellard | * in the Software without restriction, including without limitation the rights
|
9 | 85571bc7 | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 85571bc7 | bellard | * copies of the Software, and to permit persons to whom the Software is
|
11 | 85571bc7 | bellard | * furnished to do so, subject to the following conditions:
|
12 | 85571bc7 | bellard | *
|
13 | 85571bc7 | bellard | * The above copyright notice and this permission notice shall be included in
|
14 | 85571bc7 | bellard | * all copies or substantial portions of the Software.
|
15 | 85571bc7 | bellard | *
|
16 | 85571bc7 | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 85571bc7 | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 85571bc7 | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 85571bc7 | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 85571bc7 | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 85571bc7 | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 85571bc7 | bellard | * THE SOFTWARE.
|
23 | 85571bc7 | bellard | */
|
24 | 85571bc7 | bellard | #include <assert.h> |
25 | 85571bc7 | bellard | #include "vl.h" |
26 | 85571bc7 | bellard | |
27 | 85571bc7 | bellard | #define USE_WAV_AUDIO
|
28 | 85571bc7 | bellard | |
29 | fb065187 | bellard | #include "audio/audio_int.h" |
30 | 85571bc7 | bellard | |
31 | fb065187 | bellard | #define dolog(...) AUD_log ("audio", __VA_ARGS__) |
32 | fb065187 | bellard | #ifdef DEBUG
|
33 | fb065187 | bellard | #define ldebug(...) dolog (__VA_ARGS__)
|
34 | fb065187 | bellard | #else
|
35 | fb065187 | bellard | #define ldebug(...)
|
36 | 85571bc7 | bellard | #endif
|
37 | 85571bc7 | bellard | |
38 | 85571bc7 | bellard | #define QC_AUDIO_DRV "QEMU_AUDIO_DRV" |
39 | fb065187 | bellard | #define QC_VOICES "QEMU_VOICES" |
40 | 85571bc7 | bellard | #define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT" |
41 | 85571bc7 | bellard | #define QC_FIXED_FREQ "QEMU_FIXED_FREQ" |
42 | 85571bc7 | bellard | |
43 | fb065187 | bellard | static HWVoice *hw_voices;
|
44 | 85571bc7 | bellard | |
45 | 85571bc7 | bellard | AudioState audio_state = { |
46 | 85571bc7 | bellard | 1, /* use fixed settings */ |
47 | 85571bc7 | bellard | 44100, /* fixed frequency */ |
48 | 85571bc7 | bellard | 2, /* fixed channels */ |
49 | 85571bc7 | bellard | AUD_FMT_S16, /* fixed format */
|
50 | 85571bc7 | bellard | 1, /* number of hw voices */ |
51 | 85571bc7 | bellard | -1 /* voice size */ |
52 | 85571bc7 | bellard | }; |
53 | 85571bc7 | bellard | |
54 | 85571bc7 | bellard | /* http://www.df.lth.se/~john_e/gems/gem002d.html */
|
55 | 85571bc7 | bellard | /* http://www.multi-platforms.com/Tips/PopCount.htm */
|
56 | 85571bc7 | bellard | uint32_t popcount (uint32_t u) |
57 | 85571bc7 | bellard | { |
58 | 85571bc7 | bellard | u = ((u&0x55555555) + ((u>>1)&0x55555555)); |
59 | 85571bc7 | bellard | u = ((u&0x33333333) + ((u>>2)&0x33333333)); |
60 | 85571bc7 | bellard | u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); |
61 | 85571bc7 | bellard | u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); |
62 | 85571bc7 | bellard | u = ( u&0x0000ffff) + (u>>16); |
63 | 85571bc7 | bellard | return u;
|
64 | 85571bc7 | bellard | } |
65 | 85571bc7 | bellard | |
66 | 85571bc7 | bellard | inline uint32_t lsbindex (uint32_t u)
|
67 | 85571bc7 | bellard | { |
68 | 85571bc7 | bellard | return popcount ((u&-u)-1); |
69 | 85571bc7 | bellard | } |
70 | 85571bc7 | bellard | |
71 | 85571bc7 | bellard | int audio_get_conf_int (const char *key, int defval) |
72 | 85571bc7 | bellard | { |
73 | 85571bc7 | bellard | int val = defval;
|
74 | 85571bc7 | bellard | char *strval;
|
75 | 85571bc7 | bellard | |
76 | 85571bc7 | bellard | strval = getenv (key); |
77 | 85571bc7 | bellard | if (strval) {
|
78 | 85571bc7 | bellard | val = atoi (strval); |
79 | 85571bc7 | bellard | } |
80 | 85571bc7 | bellard | |
81 | 85571bc7 | bellard | return val;
|
82 | 85571bc7 | bellard | } |
83 | 85571bc7 | bellard | |
84 | 85571bc7 | bellard | const char *audio_get_conf_str (const char *key, const char *defval) |
85 | 85571bc7 | bellard | { |
86 | 85571bc7 | bellard | const char *val = getenv (key); |
87 | 85571bc7 | bellard | if (!val)
|
88 | 85571bc7 | bellard | return defval;
|
89 | 85571bc7 | bellard | else
|
90 | 85571bc7 | bellard | return val;
|
91 | 85571bc7 | bellard | } |
92 | 85571bc7 | bellard | |
93 | fb065187 | bellard | void AUD_log (const char *cap, const char *fmt, ...) |
94 | 85571bc7 | bellard | { |
95 | 85571bc7 | bellard | va_list ap; |
96 | fb065187 | bellard | fprintf (stderr, "%s: ", cap);
|
97 | 85571bc7 | bellard | va_start (ap, fmt); |
98 | 85571bc7 | bellard | vfprintf (stderr, fmt, ap); |
99 | 85571bc7 | bellard | va_end (ap); |
100 | 85571bc7 | bellard | } |
101 | 85571bc7 | bellard | |
102 | 85571bc7 | bellard | /*
|
103 | 85571bc7 | bellard | * Soft Voice
|
104 | 85571bc7 | bellard | */
|
105 | 85571bc7 | bellard | void pcm_sw_free_resources (SWVoice *sw)
|
106 | 85571bc7 | bellard | { |
107 | 85571bc7 | bellard | if (sw->buf) qemu_free (sw->buf);
|
108 | 85571bc7 | bellard | if (sw->rate) st_rate_stop (sw->rate);
|
109 | 85571bc7 | bellard | sw->buf = NULL;
|
110 | 85571bc7 | bellard | sw->rate = NULL;
|
111 | 85571bc7 | bellard | } |
112 | 85571bc7 | bellard | |
113 | 85571bc7 | bellard | int pcm_sw_alloc_resources (SWVoice *sw)
|
114 | 85571bc7 | bellard | { |
115 | 85571bc7 | bellard | sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));
|
116 | 85571bc7 | bellard | if (!sw->buf)
|
117 | 85571bc7 | bellard | return -1; |
118 | 85571bc7 | bellard | |
119 | 85571bc7 | bellard | sw->rate = st_rate_start (sw->freq, sw->hw->freq); |
120 | 85571bc7 | bellard | if (!sw->rate) {
|
121 | 85571bc7 | bellard | qemu_free (sw->buf); |
122 | 85571bc7 | bellard | sw->buf = NULL;
|
123 | 85571bc7 | bellard | return -1; |
124 | 85571bc7 | bellard | } |
125 | 85571bc7 | bellard | return 0; |
126 | 85571bc7 | bellard | } |
127 | 85571bc7 | bellard | |
128 | 85571bc7 | bellard | void pcm_sw_fini (SWVoice *sw)
|
129 | 85571bc7 | bellard | { |
130 | 85571bc7 | bellard | pcm_sw_free_resources (sw); |
131 | 85571bc7 | bellard | } |
132 | 85571bc7 | bellard | |
133 | 85571bc7 | bellard | int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq, |
134 | 85571bc7 | bellard | int nchannels, audfmt_e fmt)
|
135 | 85571bc7 | bellard | { |
136 | 85571bc7 | bellard | int bits = 8, sign = 0; |
137 | 85571bc7 | bellard | |
138 | 85571bc7 | bellard | switch (fmt) {
|
139 | 85571bc7 | bellard | case AUD_FMT_S8:
|
140 | 85571bc7 | bellard | sign = 1;
|
141 | 85571bc7 | bellard | case AUD_FMT_U8:
|
142 | 85571bc7 | bellard | break;
|
143 | 85571bc7 | bellard | |
144 | 85571bc7 | bellard | case AUD_FMT_S16:
|
145 | 85571bc7 | bellard | sign = 1;
|
146 | 85571bc7 | bellard | case AUD_FMT_U16:
|
147 | 85571bc7 | bellard | bits = 16;
|
148 | 85571bc7 | bellard | break;
|
149 | 85571bc7 | bellard | } |
150 | 85571bc7 | bellard | |
151 | 85571bc7 | bellard | sw->hw = hw; |
152 | 85571bc7 | bellard | sw->freq = freq; |
153 | 85571bc7 | bellard | sw->fmt = fmt; |
154 | 85571bc7 | bellard | sw->nchannels = nchannels; |
155 | 85571bc7 | bellard | sw->shift = (nchannels == 2) + (bits == 16); |
156 | 85571bc7 | bellard | sw->align = (1 << sw->shift) - 1; |
157 | 85571bc7 | bellard | sw->left = 0;
|
158 | 85571bc7 | bellard | sw->pos = 0;
|
159 | 85571bc7 | bellard | sw->wpos = 0;
|
160 | 85571bc7 | bellard | sw->live = 0;
|
161 | 85571bc7 | bellard | sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq; |
162 | 85571bc7 | bellard | sw->bytes_per_second = sw->freq << sw->shift; |
163 | 85571bc7 | bellard | sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16]; |
164 | 85571bc7 | bellard | |
165 | 85571bc7 | bellard | pcm_sw_free_resources (sw); |
166 | 85571bc7 | bellard | return pcm_sw_alloc_resources (sw);
|
167 | 85571bc7 | bellard | } |
168 | 85571bc7 | bellard | |
169 | 85571bc7 | bellard | /* Hard voice */
|
170 | 85571bc7 | bellard | void pcm_hw_free_resources (HWVoice *hw)
|
171 | 85571bc7 | bellard | { |
172 | 85571bc7 | bellard | if (hw->mix_buf)
|
173 | 85571bc7 | bellard | qemu_free (hw->mix_buf); |
174 | 85571bc7 | bellard | hw->mix_buf = NULL;
|
175 | 85571bc7 | bellard | } |
176 | 85571bc7 | bellard | |
177 | 85571bc7 | bellard | int pcm_hw_alloc_resources (HWVoice *hw)
|
178 | 85571bc7 | bellard | { |
179 | 85571bc7 | bellard | hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
|
180 | 85571bc7 | bellard | if (!hw->mix_buf)
|
181 | 85571bc7 | bellard | return -1; |
182 | 85571bc7 | bellard | return 0; |
183 | 85571bc7 | bellard | } |
184 | 85571bc7 | bellard | |
185 | 85571bc7 | bellard | void pcm_hw_fini (HWVoice *hw)
|
186 | 85571bc7 | bellard | { |
187 | 85571bc7 | bellard | if (hw->active) {
|
188 | 85571bc7 | bellard | ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt);
|
189 | 85571bc7 | bellard | pcm_hw_free_resources (hw); |
190 | 85571bc7 | bellard | hw->pcm_ops->fini (hw); |
191 | 85571bc7 | bellard | memset (hw, 0, audio_state.drv->voice_size);
|
192 | 85571bc7 | bellard | } |
193 | 85571bc7 | bellard | } |
194 | 85571bc7 | bellard | |
195 | 85571bc7 | bellard | void pcm_hw_gc (HWVoice *hw)
|
196 | 85571bc7 | bellard | { |
197 | 85571bc7 | bellard | if (hw->nb_voices)
|
198 | 85571bc7 | bellard | return;
|
199 | 85571bc7 | bellard | |
200 | 85571bc7 | bellard | pcm_hw_fini (hw); |
201 | 85571bc7 | bellard | } |
202 | 85571bc7 | bellard | |
203 | 85571bc7 | bellard | int pcm_hw_get_live (HWVoice *hw)
|
204 | 85571bc7 | bellard | { |
205 | 85571bc7 | bellard | int i, alive = 0, live = hw->samples; |
206 | 85571bc7 | bellard | |
207 | 85571bc7 | bellard | for (i = 0; i < hw->nb_voices; i++) { |
208 | 85571bc7 | bellard | if (hw->pvoice[i]->live) {
|
209 | 85571bc7 | bellard | live = audio_MIN (hw->pvoice[i]->live, live); |
210 | 85571bc7 | bellard | alive += 1;
|
211 | 85571bc7 | bellard | } |
212 | 85571bc7 | bellard | } |
213 | 85571bc7 | bellard | |
214 | 85571bc7 | bellard | if (alive)
|
215 | 85571bc7 | bellard | return live;
|
216 | 85571bc7 | bellard | else
|
217 | 85571bc7 | bellard | return -1; |
218 | 85571bc7 | bellard | } |
219 | 85571bc7 | bellard | |
220 | 85571bc7 | bellard | int pcm_hw_get_live2 (HWVoice *hw, int *nb_active) |
221 | 85571bc7 | bellard | { |
222 | 85571bc7 | bellard | int i, alive = 0, live = hw->samples; |
223 | 85571bc7 | bellard | |
224 | 85571bc7 | bellard | *nb_active = 0;
|
225 | 85571bc7 | bellard | for (i = 0; i < hw->nb_voices; i++) { |
226 | 85571bc7 | bellard | if (hw->pvoice[i]->live) {
|
227 | 85571bc7 | bellard | if (hw->pvoice[i]->live < live) {
|
228 | 85571bc7 | bellard | *nb_active = hw->pvoice[i]->active != 0;
|
229 | 85571bc7 | bellard | live = hw->pvoice[i]->live; |
230 | 85571bc7 | bellard | } |
231 | 85571bc7 | bellard | alive += 1;
|
232 | 85571bc7 | bellard | } |
233 | 85571bc7 | bellard | } |
234 | 85571bc7 | bellard | |
235 | 85571bc7 | bellard | if (alive)
|
236 | 85571bc7 | bellard | return live;
|
237 | 85571bc7 | bellard | else
|
238 | 85571bc7 | bellard | return -1; |
239 | 85571bc7 | bellard | } |
240 | 85571bc7 | bellard | |
241 | 85571bc7 | bellard | void pcm_hw_dec_live (HWVoice *hw, int decr) |
242 | 85571bc7 | bellard | { |
243 | 85571bc7 | bellard | int i;
|
244 | 85571bc7 | bellard | |
245 | 85571bc7 | bellard | for (i = 0; i < hw->nb_voices; i++) { |
246 | 85571bc7 | bellard | if (hw->pvoice[i]->live) {
|
247 | 85571bc7 | bellard | hw->pvoice[i]->live -= decr; |
248 | 85571bc7 | bellard | } |
249 | 85571bc7 | bellard | } |
250 | 85571bc7 | bellard | } |
251 | 85571bc7 | bellard | |
252 | 85571bc7 | bellard | void pcm_hw_clear (HWVoice *hw, void *buf, int len) |
253 | 85571bc7 | bellard | { |
254 | 85571bc7 | bellard | if (!len)
|
255 | 85571bc7 | bellard | return;
|
256 | 85571bc7 | bellard | |
257 | 85571bc7 | bellard | switch (hw->fmt) {
|
258 | 85571bc7 | bellard | case AUD_FMT_S16:
|
259 | 85571bc7 | bellard | case AUD_FMT_S8:
|
260 | 85571bc7 | bellard | memset (buf, len << hw->shift, 0x00);
|
261 | 85571bc7 | bellard | break;
|
262 | 85571bc7 | bellard | |
263 | 85571bc7 | bellard | case AUD_FMT_U8:
|
264 | 85571bc7 | bellard | memset (buf, len << hw->shift, 0x80);
|
265 | 85571bc7 | bellard | break;
|
266 | 85571bc7 | bellard | |
267 | 85571bc7 | bellard | case AUD_FMT_U16:
|
268 | 85571bc7 | bellard | { |
269 | 85571bc7 | bellard | unsigned int i; |
270 | 85571bc7 | bellard | uint16_t *p = buf; |
271 | 85571bc7 | bellard | int shift = hw->nchannels - 1; |
272 | 85571bc7 | bellard | |
273 | 85571bc7 | bellard | for (i = 0; i < len << shift; i++) { |
274 | 85571bc7 | bellard | p[i] = INT16_MAX; |
275 | 85571bc7 | bellard | } |
276 | 85571bc7 | bellard | } |
277 | 85571bc7 | bellard | break;
|
278 | 85571bc7 | bellard | } |
279 | 85571bc7 | bellard | } |
280 | 85571bc7 | bellard | |
281 | 85571bc7 | bellard | int pcm_hw_write (SWVoice *sw, void *buf, int size) |
282 | 85571bc7 | bellard | { |
283 | 85571bc7 | bellard | int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
|
284 | 85571bc7 | bellard | int ret = 0, pos = 0; |
285 | 85571bc7 | bellard | if (!sw)
|
286 | 85571bc7 | bellard | return size;
|
287 | 85571bc7 | bellard | |
288 | 85571bc7 | bellard | hwsamples = sw->hw->samples; |
289 | 85571bc7 | bellard | samples = size >> sw->shift; |
290 | 85571bc7 | bellard | |
291 | 85571bc7 | bellard | if (!sw->live) {
|
292 | 85571bc7 | bellard | sw->wpos = sw->hw->rpos; |
293 | 85571bc7 | bellard | } |
294 | 85571bc7 | bellard | wpos = sw->wpos; |
295 | 85571bc7 | bellard | live = sw->live; |
296 | 85571bc7 | bellard | dead = hwsamples - live; |
297 | 85571bc7 | bellard | swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio; |
298 | 85571bc7 | bellard | swlim = audio_MIN (swlim, samples); |
299 | 85571bc7 | bellard | |
300 | 85571bc7 | bellard | ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n",
|
301 | 85571bc7 | bellard | size, live, dead, swlim, wpos); |
302 | 85571bc7 | bellard | if (swlim)
|
303 | 85571bc7 | bellard | sw->conv (sw->buf, buf, swlim); |
304 | 85571bc7 | bellard | |
305 | 85571bc7 | bellard | while (swlim) {
|
306 | 85571bc7 | bellard | dead = hwsamples - live; |
307 | 85571bc7 | bellard | left = hwsamples - wpos; |
308 | 85571bc7 | bellard | blck = audio_MIN (dead, left); |
309 | 85571bc7 | bellard | if (!blck) {
|
310 | 85571bc7 | bellard | /* dolog ("swlim=%d\n", swlim); */
|
311 | 85571bc7 | bellard | break;
|
312 | 85571bc7 | bellard | } |
313 | 85571bc7 | bellard | isamp = swlim; |
314 | 85571bc7 | bellard | osamp = blck; |
315 | 85571bc7 | bellard | st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp); |
316 | 85571bc7 | bellard | ret += isamp; |
317 | 85571bc7 | bellard | swlim -= isamp; |
318 | 85571bc7 | bellard | pos += isamp; |
319 | 85571bc7 | bellard | live += osamp; |
320 | 85571bc7 | bellard | wpos = (wpos + osamp) % hwsamples; |
321 | 85571bc7 | bellard | } |
322 | 85571bc7 | bellard | |
323 | 85571bc7 | bellard | sw->wpos = wpos; |
324 | 85571bc7 | bellard | sw->live = live; |
325 | 85571bc7 | bellard | return ret << sw->shift;
|
326 | 85571bc7 | bellard | } |
327 | 85571bc7 | bellard | |
328 | 85571bc7 | bellard | int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) |
329 | 85571bc7 | bellard | { |
330 | 85571bc7 | bellard | int sign = 0, bits = 8; |
331 | 85571bc7 | bellard | |
332 | 85571bc7 | bellard | pcm_hw_fini (hw); |
333 | 85571bc7 | bellard | ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt);
|
334 | 85571bc7 | bellard | if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) {
|
335 | 85571bc7 | bellard | memset (hw, 0, audio_state.drv->voice_size);
|
336 | 85571bc7 | bellard | return -1; |
337 | 85571bc7 | bellard | } |
338 | 85571bc7 | bellard | |
339 | 85571bc7 | bellard | switch (hw->fmt) {
|
340 | 85571bc7 | bellard | case AUD_FMT_S8:
|
341 | 85571bc7 | bellard | sign = 1;
|
342 | 85571bc7 | bellard | case AUD_FMT_U8:
|
343 | 85571bc7 | bellard | break;
|
344 | 85571bc7 | bellard | |
345 | 85571bc7 | bellard | case AUD_FMT_S16:
|
346 | 85571bc7 | bellard | sign = 1;
|
347 | 85571bc7 | bellard | case AUD_FMT_U16:
|
348 | 85571bc7 | bellard | bits = 16;
|
349 | 85571bc7 | bellard | break;
|
350 | 85571bc7 | bellard | } |
351 | 85571bc7 | bellard | |
352 | 85571bc7 | bellard | hw->nb_voices = 0;
|
353 | 85571bc7 | bellard | hw->active = 1;
|
354 | 85571bc7 | bellard | hw->shift = (hw->nchannels == 2) + (bits == 16); |
355 | 85571bc7 | bellard | hw->bytes_per_second = hw->freq << hw->shift; |
356 | 85571bc7 | bellard | hw->align = (1 << hw->shift) - 1; |
357 | 85571bc7 | bellard | hw->samples = hw->bufsize >> hw->shift; |
358 | 85571bc7 | bellard | hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16]; |
359 | 85571bc7 | bellard | if (pcm_hw_alloc_resources (hw)) {
|
360 | 85571bc7 | bellard | pcm_hw_fini (hw); |
361 | 85571bc7 | bellard | return -1; |
362 | 85571bc7 | bellard | } |
363 | 85571bc7 | bellard | return 0; |
364 | 85571bc7 | bellard | } |
365 | 85571bc7 | bellard | |
366 | 85571bc7 | bellard | static int dist (void *hw) |
367 | 85571bc7 | bellard | { |
368 | 85571bc7 | bellard | if (hw) {
|
369 | fb065187 | bellard | return (((uint8_t *) hw - (uint8_t *) hw_voices)
|
370 | fe2cece6 | bellard | / audio_state.drv->voice_size) + 1;
|
371 | 85571bc7 | bellard | } |
372 | 85571bc7 | bellard | else {
|
373 | 85571bc7 | bellard | return 0; |
374 | 85571bc7 | bellard | } |
375 | 85571bc7 | bellard | } |
376 | 85571bc7 | bellard | |
377 | fe2cece6 | bellard | #define ADVANCE(hw) \
|
378 | fe2cece6 | bellard | ((hw) ? advance (hw, audio_state.drv->voice_size) : hw_voices) |
379 | 85571bc7 | bellard | |
380 | 85571bc7 | bellard | HWVoice *pcm_hw_find_any (HWVoice *hw) |
381 | 85571bc7 | bellard | { |
382 | 85571bc7 | bellard | int i = dist (hw);
|
383 | 85571bc7 | bellard | for (; i < audio_state.nb_hw_voices; i++) {
|
384 | 85571bc7 | bellard | hw = ADVANCE (hw); |
385 | 85571bc7 | bellard | return hw;
|
386 | 85571bc7 | bellard | } |
387 | 85571bc7 | bellard | return NULL; |
388 | 85571bc7 | bellard | } |
389 | 85571bc7 | bellard | |
390 | 85571bc7 | bellard | HWVoice *pcm_hw_find_any_active (HWVoice *hw) |
391 | 85571bc7 | bellard | { |
392 | 85571bc7 | bellard | int i = dist (hw);
|
393 | 85571bc7 | bellard | for (; i < audio_state.nb_hw_voices; i++) {
|
394 | 85571bc7 | bellard | hw = ADVANCE (hw); |
395 | 85571bc7 | bellard | if (hw->active)
|
396 | 85571bc7 | bellard | return hw;
|
397 | 85571bc7 | bellard | } |
398 | 85571bc7 | bellard | return NULL; |
399 | 85571bc7 | bellard | } |
400 | 85571bc7 | bellard | |
401 | 85571bc7 | bellard | HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw) |
402 | 85571bc7 | bellard | { |
403 | 85571bc7 | bellard | int i = dist (hw);
|
404 | 85571bc7 | bellard | for (; i < audio_state.nb_hw_voices; i++) {
|
405 | 85571bc7 | bellard | hw = ADVANCE (hw); |
406 | 85571bc7 | bellard | if (hw->active && hw->enabled)
|
407 | 85571bc7 | bellard | return hw;
|
408 | 85571bc7 | bellard | } |
409 | 85571bc7 | bellard | return NULL; |
410 | 85571bc7 | bellard | } |
411 | 85571bc7 | bellard | |
412 | 85571bc7 | bellard | HWVoice *pcm_hw_find_any_passive (HWVoice *hw) |
413 | 85571bc7 | bellard | { |
414 | 85571bc7 | bellard | int i = dist (hw);
|
415 | 85571bc7 | bellard | for (; i < audio_state.nb_hw_voices; i++) {
|
416 | 85571bc7 | bellard | hw = ADVANCE (hw); |
417 | 85571bc7 | bellard | if (!hw->active)
|
418 | 85571bc7 | bellard | return hw;
|
419 | 85571bc7 | bellard | } |
420 | 85571bc7 | bellard | return NULL; |
421 | 85571bc7 | bellard | } |
422 | 85571bc7 | bellard | |
423 | 85571bc7 | bellard | HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq,
|
424 | 85571bc7 | bellard | int nchannels, audfmt_e fmt)
|
425 | 85571bc7 | bellard | { |
426 | 85571bc7 | bellard | while ((hw = pcm_hw_find_any_active (hw))) {
|
427 | 85571bc7 | bellard | if (hw->freq == freq &&
|
428 | 85571bc7 | bellard | hw->nchannels == nchannels && |
429 | 85571bc7 | bellard | hw->fmt == fmt) |
430 | 85571bc7 | bellard | return hw;
|
431 | 85571bc7 | bellard | } |
432 | 85571bc7 | bellard | return NULL; |
433 | 85571bc7 | bellard | } |
434 | 85571bc7 | bellard | |
435 | 85571bc7 | bellard | HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt) |
436 | 85571bc7 | bellard | { |
437 | 85571bc7 | bellard | HWVoice *hw; |
438 | 85571bc7 | bellard | |
439 | 85571bc7 | bellard | if (audio_state.fixed_format) {
|
440 | 85571bc7 | bellard | freq = audio_state.fixed_freq; |
441 | 85571bc7 | bellard | nchannels = audio_state.fixed_channels; |
442 | 85571bc7 | bellard | fmt = audio_state.fixed_fmt; |
443 | 85571bc7 | bellard | } |
444 | 85571bc7 | bellard | |
445 | 85571bc7 | bellard | hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt);
|
446 | 85571bc7 | bellard | |
447 | 85571bc7 | bellard | if (hw)
|
448 | 85571bc7 | bellard | return hw;
|
449 | 85571bc7 | bellard | |
450 | 85571bc7 | bellard | hw = pcm_hw_find_any_passive (NULL);
|
451 | 85571bc7 | bellard | if (hw) {
|
452 | 85571bc7 | bellard | hw->pcm_ops = audio_state.drv->pcm_ops; |
453 | 85571bc7 | bellard | if (!hw->pcm_ops)
|
454 | 85571bc7 | bellard | return NULL; |
455 | 85571bc7 | bellard | |
456 | 85571bc7 | bellard | if (pcm_hw_init (hw, freq, nchannels, fmt)) {
|
457 | 85571bc7 | bellard | pcm_hw_gc (hw); |
458 | 85571bc7 | bellard | return NULL; |
459 | 85571bc7 | bellard | } |
460 | 85571bc7 | bellard | else
|
461 | 85571bc7 | bellard | return hw;
|
462 | 85571bc7 | bellard | } |
463 | 85571bc7 | bellard | |
464 | 85571bc7 | bellard | return pcm_hw_find_any (NULL); |
465 | 85571bc7 | bellard | } |
466 | 85571bc7 | bellard | |
467 | 85571bc7 | bellard | int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw)
|
468 | 85571bc7 | bellard | { |
469 | 85571bc7 | bellard | SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw)); |
470 | 85571bc7 | bellard | if (!pvoice)
|
471 | 85571bc7 | bellard | return -1; |
472 | 85571bc7 | bellard | |
473 | 85571bc7 | bellard | memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw));
|
474 | 85571bc7 | bellard | qemu_free (hw->pvoice); |
475 | 85571bc7 | bellard | hw->pvoice = pvoice; |
476 | 85571bc7 | bellard | hw->pvoice[hw->nb_voices++] = sw; |
477 | 85571bc7 | bellard | return 0; |
478 | 85571bc7 | bellard | } |
479 | 85571bc7 | bellard | |
480 | 85571bc7 | bellard | int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw)
|
481 | 85571bc7 | bellard | { |
482 | 85571bc7 | bellard | int i, j;
|
483 | 85571bc7 | bellard | if (hw->nb_voices > 1) { |
484 | 85571bc7 | bellard | SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw)); |
485 | 85571bc7 | bellard | |
486 | 85571bc7 | bellard | if (!pvoice) {
|
487 | 85571bc7 | bellard | dolog ("Can not maintain consistent state (not enough memory)\n");
|
488 | 85571bc7 | bellard | return -1; |
489 | 85571bc7 | bellard | } |
490 | 85571bc7 | bellard | |
491 | 85571bc7 | bellard | for (i = 0, j = 0; i < hw->nb_voices; i++) { |
492 | 85571bc7 | bellard | if (j >= hw->nb_voices - 1) { |
493 | 85571bc7 | bellard | dolog ("Can not maintain consistent state "
|
494 | 85571bc7 | bellard | "(invariant violated)\n");
|
495 | 85571bc7 | bellard | return -1; |
496 | 85571bc7 | bellard | } |
497 | 85571bc7 | bellard | if (hw->pvoice[i] != sw)
|
498 | 85571bc7 | bellard | pvoice[j++] = hw->pvoice[i]; |
499 | 85571bc7 | bellard | } |
500 | 85571bc7 | bellard | qemu_free (hw->pvoice); |
501 | 85571bc7 | bellard | hw->pvoice = pvoice; |
502 | 85571bc7 | bellard | hw->nb_voices -= 1;
|
503 | 85571bc7 | bellard | } |
504 | 85571bc7 | bellard | else {
|
505 | 85571bc7 | bellard | qemu_free (hw->pvoice); |
506 | 85571bc7 | bellard | hw->pvoice = NULL;
|
507 | 85571bc7 | bellard | hw->nb_voices = 0;
|
508 | 85571bc7 | bellard | } |
509 | 85571bc7 | bellard | return 0; |
510 | 85571bc7 | bellard | } |
511 | 85571bc7 | bellard | |
512 | 85571bc7 | bellard | SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt) |
513 | 85571bc7 | bellard | { |
514 | 85571bc7 | bellard | SWVoice *sw; |
515 | 85571bc7 | bellard | HWVoice *hw; |
516 | 85571bc7 | bellard | |
517 | 85571bc7 | bellard | sw = qemu_mallocz (sizeof (*sw));
|
518 | 85571bc7 | bellard | if (!sw)
|
519 | 85571bc7 | bellard | goto err1;
|
520 | 85571bc7 | bellard | |
521 | 85571bc7 | bellard | hw = pcm_hw_add (freq, nchannels, fmt); |
522 | 85571bc7 | bellard | if (!hw)
|
523 | 85571bc7 | bellard | goto err2;
|
524 | 85571bc7 | bellard | |
525 | 85571bc7 | bellard | if (pcm_hw_add_sw (hw, sw))
|
526 | 85571bc7 | bellard | goto err3;
|
527 | 85571bc7 | bellard | |
528 | 85571bc7 | bellard | if (pcm_sw_init (sw, hw, freq, nchannels, fmt))
|
529 | 85571bc7 | bellard | goto err4;
|
530 | 85571bc7 | bellard | |
531 | 85571bc7 | bellard | return sw;
|
532 | 85571bc7 | bellard | |
533 | 85571bc7 | bellard | err4:
|
534 | 85571bc7 | bellard | pcm_hw_del_sw (hw, sw); |
535 | 85571bc7 | bellard | err3:
|
536 | 85571bc7 | bellard | pcm_hw_gc (hw); |
537 | 85571bc7 | bellard | err2:
|
538 | 85571bc7 | bellard | qemu_free (sw); |
539 | 85571bc7 | bellard | err1:
|
540 | 85571bc7 | bellard | return NULL; |
541 | 85571bc7 | bellard | } |
542 | 85571bc7 | bellard | |
543 | 85571bc7 | bellard | SWVoice *AUD_open (SWVoice *sw, const char *name, |
544 | 85571bc7 | bellard | int freq, int nchannels, audfmt_e fmt) |
545 | 85571bc7 | bellard | { |
546 | 85571bc7 | bellard | if (!audio_state.drv) {
|
547 | 85571bc7 | bellard | return NULL; |
548 | 85571bc7 | bellard | } |
549 | 85571bc7 | bellard | |
550 | 85571bc7 | bellard | if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) {
|
551 | 85571bc7 | bellard | return sw;
|
552 | 85571bc7 | bellard | } |
553 | 85571bc7 | bellard | |
554 | 85571bc7 | bellard | if (sw) {
|
555 | 85571bc7 | bellard | ldebug ("Different format %s %d %d %d\n",
|
556 | 85571bc7 | bellard | name, |
557 | 85571bc7 | bellard | sw->freq == freq, |
558 | 85571bc7 | bellard | sw->nchannels == nchannels, |
559 | 85571bc7 | bellard | sw->fmt == fmt); |
560 | 85571bc7 | bellard | } |
561 | 85571bc7 | bellard | |
562 | 85571bc7 | bellard | if (nchannels != 1 && nchannels != 2) { |
563 | 85571bc7 | bellard | dolog ("Bogus channel count %d for voice %s\n", nchannels, name);
|
564 | 85571bc7 | bellard | return NULL; |
565 | 85571bc7 | bellard | } |
566 | 85571bc7 | bellard | |
567 | 85571bc7 | bellard | if (!audio_state.fixed_format && sw) {
|
568 | 85571bc7 | bellard | pcm_sw_fini (sw); |
569 | 85571bc7 | bellard | pcm_hw_del_sw (sw->hw, sw); |
570 | 85571bc7 | bellard | pcm_hw_gc (sw->hw); |
571 | 85571bc7 | bellard | if (sw->name) {
|
572 | 85571bc7 | bellard | qemu_free (sw->name); |
573 | 85571bc7 | bellard | sw->name = NULL;
|
574 | 85571bc7 | bellard | } |
575 | 85571bc7 | bellard | qemu_free (sw); |
576 | 85571bc7 | bellard | sw = NULL;
|
577 | 85571bc7 | bellard | } |
578 | 85571bc7 | bellard | |
579 | 85571bc7 | bellard | if (sw) {
|
580 | 85571bc7 | bellard | HWVoice *hw = sw->hw; |
581 | 85571bc7 | bellard | if (!hw) {
|
582 | 85571bc7 | bellard | dolog ("Internal logic error voice %s has no hardware store\n",
|
583 | 85571bc7 | bellard | name); |
584 | 85571bc7 | bellard | return sw;
|
585 | 85571bc7 | bellard | } |
586 | 85571bc7 | bellard | |
587 | 85571bc7 | bellard | if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) {
|
588 | 85571bc7 | bellard | pcm_sw_fini (sw); |
589 | 85571bc7 | bellard | pcm_hw_del_sw (hw, sw); |
590 | 85571bc7 | bellard | pcm_hw_gc (hw); |
591 | 85571bc7 | bellard | if (sw->name) {
|
592 | 85571bc7 | bellard | qemu_free (sw->name); |
593 | 85571bc7 | bellard | sw->name = NULL;
|
594 | 85571bc7 | bellard | } |
595 | 85571bc7 | bellard | qemu_free (sw); |
596 | 85571bc7 | bellard | return NULL; |
597 | 85571bc7 | bellard | } |
598 | 85571bc7 | bellard | } |
599 | 85571bc7 | bellard | else {
|
600 | 85571bc7 | bellard | sw = pcm_create_voice_pair (freq, nchannels, fmt); |
601 | 85571bc7 | bellard | if (!sw) {
|
602 | 85571bc7 | bellard | dolog ("Failed to create voice %s\n", name);
|
603 | 85571bc7 | bellard | return NULL; |
604 | 85571bc7 | bellard | } |
605 | 85571bc7 | bellard | } |
606 | 85571bc7 | bellard | |
607 | 85571bc7 | bellard | if (sw->name) {
|
608 | 85571bc7 | bellard | qemu_free (sw->name); |
609 | 85571bc7 | bellard | sw->name = NULL;
|
610 | 85571bc7 | bellard | } |
611 | 85571bc7 | bellard | sw->name = qemu_strdup (name); |
612 | 85571bc7 | bellard | return sw;
|
613 | 85571bc7 | bellard | } |
614 | 85571bc7 | bellard | |
615 | fb065187 | bellard | void AUD_close (SWVoice *sw)
|
616 | fb065187 | bellard | { |
617 | fb065187 | bellard | if (!sw)
|
618 | fb065187 | bellard | return;
|
619 | fb065187 | bellard | |
620 | fb065187 | bellard | pcm_sw_fini (sw); |
621 | fb065187 | bellard | pcm_hw_del_sw (sw->hw, sw); |
622 | fb065187 | bellard | pcm_hw_gc (sw->hw); |
623 | fb065187 | bellard | if (sw->name) {
|
624 | fb065187 | bellard | qemu_free (sw->name); |
625 | fb065187 | bellard | sw->name = NULL;
|
626 | fb065187 | bellard | } |
627 | fb065187 | bellard | qemu_free (sw); |
628 | fb065187 | bellard | } |
629 | fb065187 | bellard | |
630 | 85571bc7 | bellard | int AUD_write (SWVoice *sw, void *buf, int size) |
631 | 85571bc7 | bellard | { |
632 | 85571bc7 | bellard | int bytes;
|
633 | 85571bc7 | bellard | |
634 | 85571bc7 | bellard | if (!sw->hw->enabled)
|
635 | 85571bc7 | bellard | dolog ("Writing to disabled voice %s\n", sw->name);
|
636 | 85571bc7 | bellard | bytes = sw->hw->pcm_ops->write (sw, buf, size); |
637 | 85571bc7 | bellard | return bytes;
|
638 | 85571bc7 | bellard | } |
639 | 85571bc7 | bellard | |
640 | 85571bc7 | bellard | void AUD_run (void) |
641 | 85571bc7 | bellard | { |
642 | 85571bc7 | bellard | HWVoice *hw = NULL;
|
643 | 85571bc7 | bellard | |
644 | 85571bc7 | bellard | while ((hw = pcm_hw_find_any_active_enabled (hw))) {
|
645 | 85571bc7 | bellard | int i;
|
646 | 85571bc7 | bellard | if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) { |
647 | 85571bc7 | bellard | hw->enabled = 0;
|
648 | 85571bc7 | bellard | hw->pcm_ops->ctl (hw, VOICE_DISABLE); |
649 | 85571bc7 | bellard | for (i = 0; i < hw->nb_voices; i++) { |
650 | 85571bc7 | bellard | hw->pvoice[i]->live = 0;
|
651 | 85571bc7 | bellard | /* hw->pvoice[i]->old_ticks = 0; */
|
652 | 85571bc7 | bellard | } |
653 | 85571bc7 | bellard | continue;
|
654 | 85571bc7 | bellard | } |
655 | 85571bc7 | bellard | |
656 | 85571bc7 | bellard | hw->pcm_ops->run (hw); |
657 | 85571bc7 | bellard | assert (hw->rpos < hw->samples); |
658 | 85571bc7 | bellard | for (i = 0; i < hw->nb_voices; i++) { |
659 | 85571bc7 | bellard | SWVoice *sw = hw->pvoice[i]; |
660 | 85571bc7 | bellard | if (!sw->active && !sw->live && sw->old_ticks) {
|
661 | 85571bc7 | bellard | int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks; |
662 | 85571bc7 | bellard | if (delta > audio_state.ticks_threshold) {
|
663 | 85571bc7 | bellard | ldebug ("resetting old_ticks for %s\n", sw->name);
|
664 | 85571bc7 | bellard | sw->old_ticks = 0;
|
665 | 85571bc7 | bellard | } |
666 | 85571bc7 | bellard | } |
667 | 85571bc7 | bellard | } |
668 | 85571bc7 | bellard | } |
669 | 85571bc7 | bellard | } |
670 | 85571bc7 | bellard | |
671 | 85571bc7 | bellard | int AUD_get_free (SWVoice *sw)
|
672 | 85571bc7 | bellard | { |
673 | 85571bc7 | bellard | int free;
|
674 | 85571bc7 | bellard | |
675 | 85571bc7 | bellard | if (!sw)
|
676 | 85571bc7 | bellard | return 4096; |
677 | 85571bc7 | bellard | |
678 | 85571bc7 | bellard | free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio |
679 | 85571bc7 | bellard | / INT_MAX; |
680 | 85571bc7 | bellard | |
681 | 85571bc7 | bellard | free &= ~sw->hw->align; |
682 | 85571bc7 | bellard | if (!free) return 0; |
683 | 85571bc7 | bellard | |
684 | 85571bc7 | bellard | return free;
|
685 | 85571bc7 | bellard | } |
686 | 85571bc7 | bellard | |
687 | 85571bc7 | bellard | int AUD_get_buffer_size (SWVoice *sw)
|
688 | 85571bc7 | bellard | { |
689 | 85571bc7 | bellard | return sw->hw->bufsize;
|
690 | 85571bc7 | bellard | } |
691 | 85571bc7 | bellard | |
692 | 85571bc7 | bellard | void AUD_adjust (SWVoice *sw, int bytes) |
693 | 85571bc7 | bellard | { |
694 | 85571bc7 | bellard | if (!sw)
|
695 | 85571bc7 | bellard | return;
|
696 | 85571bc7 | bellard | sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second; |
697 | 85571bc7 | bellard | } |
698 | 85571bc7 | bellard | |
699 | 85571bc7 | bellard | void AUD_reset (SWVoice *sw)
|
700 | 85571bc7 | bellard | { |
701 | 85571bc7 | bellard | sw->active = 0;
|
702 | 85571bc7 | bellard | sw->old_ticks = 0;
|
703 | 85571bc7 | bellard | } |
704 | 85571bc7 | bellard | |
705 | 85571bc7 | bellard | int AUD_calc_elapsed (SWVoice *sw)
|
706 | 85571bc7 | bellard | { |
707 | 85571bc7 | bellard | int64_t now, delta, bytes; |
708 | 85571bc7 | bellard | int dead, swlim;
|
709 | 85571bc7 | bellard | |
710 | 85571bc7 | bellard | if (!sw)
|
711 | 85571bc7 | bellard | return 0; |
712 | 85571bc7 | bellard | |
713 | 85571bc7 | bellard | now = qemu_get_clock (vm_clock); |
714 | 85571bc7 | bellard | delta = now - sw->old_ticks; |
715 | 85571bc7 | bellard | bytes = (delta * sw->bytes_per_second) / ticks_per_sec; |
716 | 85571bc7 | bellard | if (delta < 0) { |
717 | 85571bc7 | bellard | dolog ("whoops delta(<0)=%lld\n", delta);
|
718 | 85571bc7 | bellard | return 0; |
719 | 85571bc7 | bellard | } |
720 | 85571bc7 | bellard | |
721 | 85571bc7 | bellard | dead = sw->hw->samples - sw->live; |
722 | 85571bc7 | bellard | swlim = ((dead * (int64_t) INT_MAX) / sw->ratio); |
723 | 85571bc7 | bellard | |
724 | 85571bc7 | bellard | if (bytes > swlim) {
|
725 | 85571bc7 | bellard | return swlim;
|
726 | 85571bc7 | bellard | } |
727 | 85571bc7 | bellard | else {
|
728 | 85571bc7 | bellard | return bytes;
|
729 | 85571bc7 | bellard | } |
730 | 85571bc7 | bellard | } |
731 | 85571bc7 | bellard | |
732 | 85571bc7 | bellard | void AUD_enable (SWVoice *sw, int on) |
733 | 85571bc7 | bellard | { |
734 | 85571bc7 | bellard | int i;
|
735 | 85571bc7 | bellard | HWVoice *hw; |
736 | 85571bc7 | bellard | |
737 | 85571bc7 | bellard | if (!sw)
|
738 | 85571bc7 | bellard | return;
|
739 | 85571bc7 | bellard | |
740 | 85571bc7 | bellard | hw = sw->hw; |
741 | 85571bc7 | bellard | if (on) {
|
742 | 85571bc7 | bellard | if (!sw->live)
|
743 | 85571bc7 | bellard | sw->wpos = sw->hw->rpos; |
744 | 85571bc7 | bellard | if (!sw->old_ticks) {
|
745 | 85571bc7 | bellard | sw->old_ticks = qemu_get_clock (vm_clock); |
746 | 85571bc7 | bellard | } |
747 | 85571bc7 | bellard | } |
748 | 85571bc7 | bellard | |
749 | 85571bc7 | bellard | if (sw->active != on) {
|
750 | 85571bc7 | bellard | if (on) {
|
751 | 85571bc7 | bellard | hw->pending_disable = 0;
|
752 | 85571bc7 | bellard | if (!hw->enabled) {
|
753 | 85571bc7 | bellard | hw->enabled = 1;
|
754 | 85571bc7 | bellard | for (i = 0; i < hw->nb_voices; i++) { |
755 | 85571bc7 | bellard | ldebug ("resetting voice\n");
|
756 | 85571bc7 | bellard | sw = hw->pvoice[i]; |
757 | 85571bc7 | bellard | sw->old_ticks = qemu_get_clock (vm_clock); |
758 | 85571bc7 | bellard | } |
759 | 85571bc7 | bellard | hw->pcm_ops->ctl (hw, VOICE_ENABLE); |
760 | 85571bc7 | bellard | } |
761 | 85571bc7 | bellard | } |
762 | 85571bc7 | bellard | else {
|
763 | 85571bc7 | bellard | if (hw->enabled && !hw->pending_disable) {
|
764 | 85571bc7 | bellard | int nb_active = 0; |
765 | 85571bc7 | bellard | for (i = 0; i < hw->nb_voices; i++) { |
766 | 85571bc7 | bellard | nb_active += hw->pvoice[i]->active != 0;
|
767 | 85571bc7 | bellard | } |
768 | 85571bc7 | bellard | |
769 | 85571bc7 | bellard | if (nb_active == 1) { |
770 | 85571bc7 | bellard | hw->pending_disable = 1;
|
771 | 85571bc7 | bellard | } |
772 | 85571bc7 | bellard | } |
773 | 85571bc7 | bellard | } |
774 | 85571bc7 | bellard | sw->active = on; |
775 | 85571bc7 | bellard | } |
776 | 85571bc7 | bellard | } |
777 | 85571bc7 | bellard | |
778 | 85571bc7 | bellard | static struct audio_output_driver *drvtab[] = { |
779 | fb065187 | bellard | #ifdef CONFIG_OSS
|
780 | 85571bc7 | bellard | &oss_output_driver, |
781 | 85571bc7 | bellard | #endif
|
782 | 102a52e4 | bellard | #ifdef CONFIG_FMOD
|
783 | 85571bc7 | bellard | &fmod_output_driver, |
784 | 85571bc7 | bellard | #endif
|
785 | fb065187 | bellard | #ifdef CONFIG_SDL
|
786 | 85571bc7 | bellard | &sdl_output_driver, |
787 | 85571bc7 | bellard | #endif
|
788 | 7372f88d | bellard | &no_output_driver, |
789 | 85571bc7 | bellard | #ifdef USE_WAV_AUDIO
|
790 | 85571bc7 | bellard | &wav_output_driver, |
791 | 85571bc7 | bellard | #endif
|
792 | 85571bc7 | bellard | }; |
793 | 85571bc7 | bellard | |
794 | 85571bc7 | bellard | static int voice_init (struct audio_output_driver *drv) |
795 | 85571bc7 | bellard | { |
796 | 85571bc7 | bellard | audio_state.opaque = drv->init (); |
797 | 85571bc7 | bellard | if (audio_state.opaque) {
|
798 | 85571bc7 | bellard | if (audio_state.nb_hw_voices > drv->max_voices) {
|
799 | 85571bc7 | bellard | dolog ("`%s' does not support %d multiple hardware channels\n"
|
800 | 85571bc7 | bellard | "Resetting to %d\n",
|
801 | 85571bc7 | bellard | drv->name, audio_state.nb_hw_voices, drv->max_voices); |
802 | 85571bc7 | bellard | audio_state.nb_hw_voices = drv->max_voices; |
803 | 85571bc7 | bellard | } |
804 | fb065187 | bellard | hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size); |
805 | fb065187 | bellard | if (hw_voices) {
|
806 | 85571bc7 | bellard | audio_state.drv = drv; |
807 | 85571bc7 | bellard | return 1; |
808 | 85571bc7 | bellard | } |
809 | 85571bc7 | bellard | else {
|
810 | 85571bc7 | bellard | dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n",
|
811 | 85571bc7 | bellard | audio_state.nb_hw_voices, drv->name, drv->voice_size); |
812 | 85571bc7 | bellard | drv->fini (audio_state.opaque); |
813 | 85571bc7 | bellard | return 0; |
814 | 85571bc7 | bellard | } |
815 | 85571bc7 | bellard | } |
816 | 85571bc7 | bellard | else {
|
817 | 85571bc7 | bellard | dolog ("Could not init `%s' audio\n", drv->name);
|
818 | 85571bc7 | bellard | return 0; |
819 | 85571bc7 | bellard | } |
820 | 85571bc7 | bellard | } |
821 | 85571bc7 | bellard | |
822 | 85571bc7 | bellard | static void audio_vm_stop_handler (void *opaque, int reason) |
823 | 85571bc7 | bellard | { |
824 | 85571bc7 | bellard | HWVoice *hw = NULL;
|
825 | 85571bc7 | bellard | |
826 | 85571bc7 | bellard | while ((hw = pcm_hw_find_any (hw))) {
|
827 | 85571bc7 | bellard | if (!hw->pcm_ops)
|
828 | 85571bc7 | bellard | continue;
|
829 | 85571bc7 | bellard | |
830 | 85571bc7 | bellard | hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE); |
831 | 85571bc7 | bellard | } |
832 | 85571bc7 | bellard | } |
833 | 85571bc7 | bellard | |
834 | 85571bc7 | bellard | static void audio_atexit (void) |
835 | 85571bc7 | bellard | { |
836 | 85571bc7 | bellard | HWVoice *hw = NULL;
|
837 | 85571bc7 | bellard | |
838 | 85571bc7 | bellard | while ((hw = pcm_hw_find_any (hw))) {
|
839 | 85571bc7 | bellard | if (!hw->pcm_ops)
|
840 | 85571bc7 | bellard | continue;
|
841 | 85571bc7 | bellard | |
842 | 85571bc7 | bellard | hw->pcm_ops->ctl (hw, VOICE_DISABLE); |
843 | 85571bc7 | bellard | hw->pcm_ops->fini (hw); |
844 | 85571bc7 | bellard | } |
845 | 85571bc7 | bellard | audio_state.drv->fini (audio_state.opaque); |
846 | 85571bc7 | bellard | } |
847 | 85571bc7 | bellard | |
848 | 85571bc7 | bellard | static void audio_save (QEMUFile *f, void *opaque) |
849 | 85571bc7 | bellard | { |
850 | 85571bc7 | bellard | } |
851 | 85571bc7 | bellard | |
852 | 85571bc7 | bellard | static int audio_load (QEMUFile *f, void *opaque, int version_id) |
853 | 85571bc7 | bellard | { |
854 | 85571bc7 | bellard | if (version_id != 1) |
855 | 85571bc7 | bellard | return -EINVAL;
|
856 | 85571bc7 | bellard | |
857 | 85571bc7 | bellard | return 0; |
858 | 85571bc7 | bellard | } |
859 | 85571bc7 | bellard | |
860 | 85571bc7 | bellard | void AUD_init (void) |
861 | 85571bc7 | bellard | { |
862 | 85571bc7 | bellard | int i;
|
863 | 85571bc7 | bellard | int done = 0; |
864 | 85571bc7 | bellard | const char *drvname; |
865 | 85571bc7 | bellard | |
866 | 85571bc7 | bellard | audio_state.fixed_format = |
867 | 85571bc7 | bellard | !!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format); |
868 | 85571bc7 | bellard | audio_state.fixed_freq = |
869 | 85571bc7 | bellard | audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq); |
870 | 85571bc7 | bellard | audio_state.nb_hw_voices = |
871 | 85571bc7 | bellard | audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices); |
872 | 85571bc7 | bellard | |
873 | 85571bc7 | bellard | if (audio_state.nb_hw_voices <= 0) { |
874 | 85571bc7 | bellard | dolog ("Bogus number of voices %d, resetting to 1\n",
|
875 | 85571bc7 | bellard | audio_state.nb_hw_voices); |
876 | 85571bc7 | bellard | } |
877 | 85571bc7 | bellard | |
878 | 85571bc7 | bellard | drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL);
|
879 | 85571bc7 | bellard | if (drvname) {
|
880 | 85571bc7 | bellard | int found = 0; |
881 | 85571bc7 | bellard | for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { |
882 | 85571bc7 | bellard | if (!strcmp (drvname, drvtab[i]->name)) {
|
883 | 85571bc7 | bellard | done = voice_init (drvtab[i]); |
884 | 85571bc7 | bellard | found = 1;
|
885 | 85571bc7 | bellard | break;
|
886 | 85571bc7 | bellard | } |
887 | 85571bc7 | bellard | } |
888 | 85571bc7 | bellard | if (!found) {
|
889 | 85571bc7 | bellard | dolog ("Unknown audio driver `%s'\n", drvname);
|
890 | 85571bc7 | bellard | } |
891 | 85571bc7 | bellard | } |
892 | 85571bc7 | bellard | |
893 | 85571bc7 | bellard | qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL);
|
894 | 85571bc7 | bellard | atexit (audio_atexit); |
895 | 85571bc7 | bellard | |
896 | 85571bc7 | bellard | if (!done) {
|
897 | 85571bc7 | bellard | for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { |
898 | 85571bc7 | bellard | if (drvtab[i]->can_be_default)
|
899 | 85571bc7 | bellard | done = voice_init (drvtab[i]); |
900 | 85571bc7 | bellard | } |
901 | 85571bc7 | bellard | } |
902 | 85571bc7 | bellard | |
903 | 85571bc7 | bellard | audio_state.ticks_threshold = ticks_per_sec / 50;
|
904 | 85571bc7 | bellard | audio_state.freq_threshold = 100;
|
905 | 85571bc7 | bellard | |
906 | 85571bc7 | bellard | register_savevm ("audio", 0, 1, audio_save, audio_load, NULL); |
907 | 85571bc7 | bellard | if (!done) {
|
908 | 85571bc7 | bellard | dolog ("Can not initialize audio subsystem\n");
|
909 | 7372f88d | bellard | voice_init (&no_output_driver); |
910 | 85571bc7 | bellard | } |
911 | 85571bc7 | bellard | } |