Commit f941aa256f2254c3f35f00fcf5d7f20dba55a5b7
1 parent
b93aebec
Qemu support for S32 and U32 alsa output, by Vassili Karpov.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2427 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
9 changed files
with
214 additions
and
48 deletions
audio/alsaaudio.c
... | ... | @@ -157,6 +157,12 @@ static int aud_to_alsafmt (audfmt_e fmt) |
157 | 157 | case AUD_FMT_U16: |
158 | 158 | return SND_PCM_FORMAT_U16_LE; |
159 | 159 | |
160 | + case AUD_FMT_S32: | |
161 | + return SND_PCM_FORMAT_S32_LE; | |
162 | + | |
163 | + case AUD_FMT_U32: | |
164 | + return SND_PCM_FORMAT_U32_LE; | |
165 | + | |
160 | 166 | default: |
161 | 167 | dolog ("Internal logic error: Bad audio format %d\n", fmt); |
162 | 168 | #ifdef DEBUG_AUDIO |
... | ... | @@ -199,6 +205,26 @@ static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness) |
199 | 205 | *fmt = AUD_FMT_U16; |
200 | 206 | break; |
201 | 207 | |
208 | + case SND_PCM_FORMAT_S32_LE: | |
209 | + *endianness = 0; | |
210 | + *fmt = AUD_FMT_S32; | |
211 | + break; | |
212 | + | |
213 | + case SND_PCM_FORMAT_U32_LE: | |
214 | + *endianness = 0; | |
215 | + *fmt = AUD_FMT_U32; | |
216 | + break; | |
217 | + | |
218 | + case SND_PCM_FORMAT_S32_BE: | |
219 | + *endianness = 1; | |
220 | + *fmt = AUD_FMT_S32; | |
221 | + break; | |
222 | + | |
223 | + case SND_PCM_FORMAT_U32_BE: | |
224 | + *endianness = 1; | |
225 | + *fmt = AUD_FMT_U32; | |
226 | + break; | |
227 | + | |
202 | 228 | default: |
203 | 229 | dolog ("Unrecognized audio format %d\n", alsafmt); |
204 | 230 | return -1; | ... | ... |
audio/audio.c
... | ... | @@ -80,7 +80,8 @@ static struct { |
80 | 80 | { |
81 | 81 | 44100, /* freq */ |
82 | 82 | 2, /* nchannels */ |
83 | - AUD_FMT_S16 /* fmt */ | |
83 | + AUD_FMT_S16, /* fmt */ | |
84 | + AUDIO_HOST_ENDIANNESS | |
84 | 85 | } |
85 | 86 | }, |
86 | 87 | |
... | ... | @@ -91,7 +92,8 @@ static struct { |
91 | 92 | { |
92 | 93 | 44100, /* freq */ |
93 | 94 | 2, /* nchannels */ |
94 | - AUD_FMT_S16 /* fmt */ | |
95 | + AUD_FMT_S16, /* fmt */ | |
96 | + AUDIO_HOST_ENDIANNESS | |
95 | 97 | } |
96 | 98 | }, |
97 | 99 | |
... | ... | @@ -166,6 +168,25 @@ int audio_bug (const char *funcname, int cond) |
166 | 168 | } |
167 | 169 | #endif |
168 | 170 | |
171 | +static inline int audio_bits_to_index (int bits) | |
172 | +{ | |
173 | + switch (bits) { | |
174 | + case 8: | |
175 | + return 0; | |
176 | + | |
177 | + case 16: | |
178 | + return 1; | |
179 | + | |
180 | + case 32: | |
181 | + return 2; | |
182 | + | |
183 | + default: | |
184 | + audio_bug ("bits_to_index", 1); | |
185 | + AUD_log (NULL, "invalid bits %d\n", bits); | |
186 | + return 0; | |
187 | + } | |
188 | +} | |
189 | + | |
169 | 190 | void *audio_calloc (const char *funcname, int nmemb, size_t size) |
170 | 191 | { |
171 | 192 | int cond; |
... | ... | @@ -227,6 +248,12 @@ const char *audio_audfmt_to_string (audfmt_e fmt) |
227 | 248 | |
228 | 249 | case AUD_FMT_S16: |
229 | 250 | return "S16"; |
251 | + | |
252 | + case AUD_FMT_U32: | |
253 | + return "U32"; | |
254 | + | |
255 | + case AUD_FMT_S32: | |
256 | + return "S32"; | |
230 | 257 | } |
231 | 258 | |
232 | 259 | dolog ("Bogus audfmt %d returning S16\n", fmt); |
... | ... | @@ -243,6 +270,10 @@ audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp) |
243 | 270 | *defaultp = 0; |
244 | 271 | return AUD_FMT_U16; |
245 | 272 | } |
273 | + else if (!strcasecmp (s, "u32")) { | |
274 | + *defaultp = 0; | |
275 | + return AUD_FMT_U32; | |
276 | + } | |
246 | 277 | else if (!strcasecmp (s, "s8")) { |
247 | 278 | *defaultp = 0; |
248 | 279 | return AUD_FMT_S8; |
... | ... | @@ -251,6 +282,10 @@ audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp) |
251 | 282 | *defaultp = 0; |
252 | 283 | return AUD_FMT_S16; |
253 | 284 | } |
285 | + else if (!strcasecmp (s, "s32")) { | |
286 | + *defaultp = 0; | |
287 | + return AUD_FMT_S32; | |
288 | + } | |
254 | 289 | else { |
255 | 290 | dolog ("Bogus audio format `%s' using %s\n", |
256 | 291 | s, audio_audfmt_to_string (defval)); |
... | ... | @@ -538,6 +573,8 @@ static int audio_validate_settings (audsettings_t *as) |
538 | 573 | case AUD_FMT_U8: |
539 | 574 | case AUD_FMT_S16: |
540 | 575 | case AUD_FMT_U16: |
576 | + case AUD_FMT_S32: | |
577 | + case AUD_FMT_U32: | |
541 | 578 | break; |
542 | 579 | default: |
543 | 580 | invalid = 1; |
... | ... | @@ -563,6 +600,12 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) |
563 | 600 | case AUD_FMT_U16: |
564 | 601 | bits = 16; |
565 | 602 | break; |
603 | + | |
604 | + case AUD_FMT_S32: | |
605 | + sign = 1; | |
606 | + case AUD_FMT_U32: | |
607 | + bits = 32; | |
608 | + break; | |
566 | 609 | } |
567 | 610 | return info->freq == as->freq |
568 | 611 | && info->nchannels == as->nchannels |
... | ... | @@ -573,7 +616,7 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) |
573 | 616 | |
574 | 617 | void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) |
575 | 618 | { |
576 | - int bits = 8, sign = 0; | |
619 | + int bits = 8, sign = 0, shift = 0; | |
577 | 620 | |
578 | 621 | switch (as->fmt) { |
579 | 622 | case AUD_FMT_S8: |
... | ... | @@ -585,6 +628,14 @@ void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) |
585 | 628 | sign = 1; |
586 | 629 | case AUD_FMT_U16: |
587 | 630 | bits = 16; |
631 | + shift = 1; | |
632 | + break; | |
633 | + | |
634 | + case AUD_FMT_S32: | |
635 | + sign = 1; | |
636 | + case AUD_FMT_U32: | |
637 | + bits = 32; | |
638 | + shift = 2; | |
588 | 639 | break; |
589 | 640 | } |
590 | 641 | |
... | ... | @@ -592,7 +643,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) |
592 | 643 | info->bits = bits; |
593 | 644 | info->sign = sign; |
594 | 645 | info->nchannels = as->nchannels; |
595 | - info->shift = (as->nchannels == 2) + (bits == 16); | |
646 | + info->shift = (as->nchannels == 2) + shift; | |
596 | 647 | info->align = (1 << info->shift) - 1; |
597 | 648 | info->bytes_per_second = info->freq << info->shift; |
598 | 649 | info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS); |
... | ... | @@ -608,22 +659,49 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) |
608 | 659 | memset (buf, 0x00, len << info->shift); |
609 | 660 | } |
610 | 661 | else { |
611 | - if (info->bits == 8) { | |
662 | + switch (info->bits) { | |
663 | + case 8: | |
612 | 664 | memset (buf, 0x80, len << info->shift); |
613 | - } | |
614 | - else { | |
615 | - int i; | |
616 | - uint16_t *p = buf; | |
617 | - int shift = info->nchannels - 1; | |
618 | - short s = INT16_MAX; | |
665 | + break; | |
619 | 666 | |
620 | - if (info->swap_endianness) { | |
621 | - s = bswap16 (s); | |
667 | + case 16: | |
668 | + { | |
669 | + int i; | |
670 | + uint16_t *p = buf; | |
671 | + int shift = info->nchannels - 1; | |
672 | + short s = INT16_MAX; | |
673 | + | |
674 | + if (info->swap_endianness) { | |
675 | + s = bswap16 (s); | |
676 | + } | |
677 | + | |
678 | + for (i = 0; i < len << shift; i++) { | |
679 | + p[i] = s; | |
680 | + } | |
622 | 681 | } |
682 | + break; | |
683 | + | |
684 | + case 32: | |
685 | + { | |
686 | + int i; | |
687 | + uint32_t *p = buf; | |
688 | + int shift = info->nchannels - 1; | |
689 | + int32_t s = INT32_MAX; | |
690 | + | |
691 | + if (info->swap_endianness) { | |
692 | + s = bswap32 (s); | |
693 | + } | |
623 | 694 | |
624 | - for (i = 0; i < len << shift; i++) { | |
625 | - p[i] = s; | |
695 | + for (i = 0; i < len << shift; i++) { | |
696 | + p[i] = s; | |
697 | + } | |
626 | 698 | } |
699 | + break; | |
700 | + | |
701 | + default: | |
702 | + AUD_log (NULL, "audio_pcm_info_clear_buf: invalid bits %d\n", | |
703 | + info->bits); | |
704 | + break; | |
627 | 705 | } |
628 | 706 | } |
629 | 707 | } |
... | ... | @@ -1811,7 +1889,7 @@ CaptureVoiceOut *AUD_add_capture ( |
1811 | 1889 | [hw->info.nchannels == 2] |
1812 | 1890 | [hw->info.sign] |
1813 | 1891 | [hw->info.swap_endianness] |
1814 | - [hw->info.bits == 16]; | |
1892 | + [audio_bits_to_index (hw->info.bits)]; | |
1815 | 1893 | |
1816 | 1894 | LIST_INSERT_HEAD (&s->cap_head, cap, entries); |
1817 | 1895 | LIST_INSERT_HEAD (&cap->cb_head, cb, entries); | ... | ... |
audio/audio.h
audio/audio_template.h
... | ... | @@ -164,7 +164,7 @@ static int glue (audio_pcm_sw_init_, TYPE) ( |
164 | 164 | [sw->info.nchannels == 2] |
165 | 165 | [sw->info.sign] |
166 | 166 | [sw->info.swap_endianness] |
167 | - [sw->info.bits == 16]; | |
167 | + [audio_bits_to_index (sw->info.bits)]; | |
168 | 168 | |
169 | 169 | sw->name = qemu_strdup (name); |
170 | 170 | err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); |
... | ... | @@ -288,7 +288,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) |
288 | 288 | [hw->info.nchannels == 2] |
289 | 289 | [hw->info.sign] |
290 | 290 | [hw->info.swap_endianness] |
291 | - [hw->info.bits == 16]; | |
291 | + [audio_bits_to_index (hw->info.bits)]; | |
292 | 292 | |
293 | 293 | if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { |
294 | 294 | goto err1; | ... | ... |
audio/coreaudio.c
... | ... | @@ -294,7 +294,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) |
294 | 294 | coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; |
295 | 295 | UInt32 propertySize; |
296 | 296 | int err; |
297 | - int bits = 8; | |
298 | 297 | const char *typ = "playback"; |
299 | 298 | AudioValueRange frameRange; |
300 | 299 | |
... | ... | @@ -305,10 +304,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) |
305 | 304 | return -1; |
306 | 305 | } |
307 | 306 | |
308 | - if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) { | |
309 | - bits = 16; | |
310 | - } | |
311 | - | |
312 | 307 | audio_pcm_init_info (&hw->info, as); |
313 | 308 | |
314 | 309 | /* open default output device */ | ... | ... |
audio/mixeng.c
... | ... | @@ -82,6 +82,7 @@ |
82 | 82 | #undef IN_T |
83 | 83 | #undef SHIFT |
84 | 84 | |
85 | +/* Unsigned 16 bit */ | |
85 | 86 | #define IN_T uint16_t |
86 | 87 | #define IN_MIN 0 |
87 | 88 | #define IN_MAX USHRT_MAX |
... | ... | @@ -101,26 +102,72 @@ |
101 | 102 | #undef IN_T |
102 | 103 | #undef SHIFT |
103 | 104 | |
104 | -t_sample *mixeng_conv[2][2][2][2] = { | |
105 | +/* Signed 32 bit */ | |
106 | +#define IN_T int32_t | |
107 | +#define IN_MIN INT32_MIN | |
108 | +#define IN_MAX INT32_MAX | |
109 | +#define SIGNED | |
110 | +#define SHIFT 32 | |
111 | +#define ENDIAN_CONVERSION natural | |
112 | +#define ENDIAN_CONVERT(v) (v) | |
113 | +#include "mixeng_template.h" | |
114 | +#undef ENDIAN_CONVERT | |
115 | +#undef ENDIAN_CONVERSION | |
116 | +#define ENDIAN_CONVERSION swap | |
117 | +#define ENDIAN_CONVERT(v) bswap32 (v) | |
118 | +#include "mixeng_template.h" | |
119 | +#undef ENDIAN_CONVERT | |
120 | +#undef ENDIAN_CONVERSION | |
121 | +#undef SIGNED | |
122 | +#undef IN_MAX | |
123 | +#undef IN_MIN | |
124 | +#undef IN_T | |
125 | +#undef SHIFT | |
126 | + | |
127 | +/* Unsigned 16 bit */ | |
128 | +#define IN_T uint32_t | |
129 | +#define IN_MIN 0 | |
130 | +#define IN_MAX UINT32_MAX | |
131 | +#define SHIFT 32 | |
132 | +#define ENDIAN_CONVERSION natural | |
133 | +#define ENDIAN_CONVERT(v) (v) | |
134 | +#include "mixeng_template.h" | |
135 | +#undef ENDIAN_CONVERT | |
136 | +#undef ENDIAN_CONVERSION | |
137 | +#define ENDIAN_CONVERSION swap | |
138 | +#define ENDIAN_CONVERT(v) bswap32 (v) | |
139 | +#include "mixeng_template.h" | |
140 | +#undef ENDIAN_CONVERT | |
141 | +#undef ENDIAN_CONVERSION | |
142 | +#undef IN_MAX | |
143 | +#undef IN_MIN | |
144 | +#undef IN_T | |
145 | +#undef SHIFT | |
146 | + | |
147 | +t_sample *mixeng_conv[2][2][2][3] = { | |
105 | 148 | { |
106 | 149 | { |
107 | 150 | { |
108 | 151 | conv_natural_uint8_t_to_mono, |
109 | - conv_natural_uint16_t_to_mono | |
152 | + conv_natural_uint16_t_to_mono, | |
153 | + conv_natural_uint32_t_to_mono | |
110 | 154 | }, |
111 | 155 | { |
112 | 156 | conv_natural_uint8_t_to_mono, |
113 | - conv_swap_uint16_t_to_mono | |
157 | + conv_swap_uint16_t_to_mono, | |
158 | + conv_swap_uint32_t_to_mono, | |
114 | 159 | } |
115 | 160 | }, |
116 | 161 | { |
117 | 162 | { |
118 | 163 | conv_natural_int8_t_to_mono, |
119 | - conv_natural_int16_t_to_mono | |
164 | + conv_natural_int16_t_to_mono, | |
165 | + conv_natural_int32_t_to_mono | |
120 | 166 | }, |
121 | 167 | { |
122 | 168 | conv_natural_int8_t_to_mono, |
123 | - conv_swap_int16_t_to_mono | |
169 | + conv_swap_int16_t_to_mono, | |
170 | + conv_swap_int32_t_to_mono | |
124 | 171 | } |
125 | 172 | } |
126 | 173 | }, |
... | ... | @@ -128,46 +175,54 @@ t_sample *mixeng_conv[2][2][2][2] = { |
128 | 175 | { |
129 | 176 | { |
130 | 177 | conv_natural_uint8_t_to_stereo, |
131 | - conv_natural_uint16_t_to_stereo | |
178 | + conv_natural_uint16_t_to_stereo, | |
179 | + conv_natural_uint32_t_to_stereo | |
132 | 180 | }, |
133 | 181 | { |
134 | 182 | conv_natural_uint8_t_to_stereo, |
135 | - conv_swap_uint16_t_to_stereo | |
183 | + conv_swap_uint16_t_to_stereo, | |
184 | + conv_swap_uint32_t_to_stereo | |
136 | 185 | } |
137 | 186 | }, |
138 | 187 | { |
139 | 188 | { |
140 | 189 | conv_natural_int8_t_to_stereo, |
141 | - conv_natural_int16_t_to_stereo | |
190 | + conv_natural_int16_t_to_stereo, | |
191 | + conv_natural_int32_t_to_stereo | |
142 | 192 | }, |
143 | 193 | { |
144 | 194 | conv_natural_int8_t_to_stereo, |
145 | - conv_swap_int16_t_to_stereo | |
195 | + conv_swap_int16_t_to_stereo, | |
196 | + conv_swap_int32_t_to_stereo, | |
146 | 197 | } |
147 | 198 | } |
148 | 199 | } |
149 | 200 | }; |
150 | 201 | |
151 | -f_sample *mixeng_clip[2][2][2][2] = { | |
202 | +f_sample *mixeng_clip[2][2][2][3] = { | |
152 | 203 | { |
153 | 204 | { |
154 | 205 | { |
155 | 206 | clip_natural_uint8_t_from_mono, |
156 | - clip_natural_uint16_t_from_mono | |
207 | + clip_natural_uint16_t_from_mono, | |
208 | + clip_natural_uint32_t_from_mono | |
157 | 209 | }, |
158 | 210 | { |
159 | 211 | clip_natural_uint8_t_from_mono, |
160 | - clip_swap_uint16_t_from_mono | |
212 | + clip_swap_uint16_t_from_mono, | |
213 | + clip_swap_uint32_t_from_mono | |
161 | 214 | } |
162 | 215 | }, |
163 | 216 | { |
164 | 217 | { |
165 | 218 | clip_natural_int8_t_from_mono, |
166 | - clip_natural_int16_t_from_mono | |
219 | + clip_natural_int16_t_from_mono, | |
220 | + clip_natural_int32_t_from_mono | |
167 | 221 | }, |
168 | 222 | { |
169 | 223 | clip_natural_int8_t_from_mono, |
170 | - clip_swap_int16_t_from_mono | |
224 | + clip_swap_int16_t_from_mono, | |
225 | + clip_swap_int32_t_from_mono | |
171 | 226 | } |
172 | 227 | } |
173 | 228 | }, |
... | ... | @@ -175,21 +230,25 @@ f_sample *mixeng_clip[2][2][2][2] = { |
175 | 230 | { |
176 | 231 | { |
177 | 232 | clip_natural_uint8_t_from_stereo, |
178 | - clip_natural_uint16_t_from_stereo | |
233 | + clip_natural_uint16_t_from_stereo, | |
234 | + clip_natural_uint32_t_from_stereo | |
179 | 235 | }, |
180 | 236 | { |
181 | 237 | clip_natural_uint8_t_from_stereo, |
182 | - clip_swap_uint16_t_from_stereo | |
238 | + clip_swap_uint16_t_from_stereo, | |
239 | + clip_swap_uint32_t_from_stereo | |
183 | 240 | } |
184 | 241 | }, |
185 | 242 | { |
186 | 243 | { |
187 | 244 | clip_natural_int8_t_from_stereo, |
188 | - clip_natural_int16_t_from_stereo | |
245 | + clip_natural_int16_t_from_stereo, | |
246 | + clip_natural_int32_t_from_stereo | |
189 | 247 | }, |
190 | 248 | { |
191 | 249 | clip_natural_int8_t_from_stereo, |
192 | - clip_swap_int16_t_from_stereo | |
250 | + clip_swap_int16_t_from_stereo, | |
251 | + clip_swap_int32_t_from_stereo | |
193 | 252 | } |
194 | 253 | } |
195 | 254 | } | ... | ... |
audio/mixeng.h
... | ... | @@ -37,8 +37,8 @@ typedef void (t_sample) (st_sample_t *dst, const void *src, |
37 | 37 | int samples, volume_t *vol); |
38 | 38 | typedef void (f_sample) (void *dst, const st_sample_t *src, int samples); |
39 | 39 | |
40 | -extern t_sample *mixeng_conv[2][2][2][2]; | |
41 | -extern f_sample *mixeng_clip[2][2][2][2]; | |
40 | +extern t_sample *mixeng_conv[2][2][2][3]; | |
41 | +extern f_sample *mixeng_clip[2][2][2][3]; | |
42 | 42 | |
43 | 43 | void *st_rate_start (int inrate, int outrate); |
44 | 44 | void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, | ... | ... |
audio/wavaudio.c
... | ... | @@ -41,7 +41,8 @@ static struct { |
41 | 41 | { |
42 | 42 | 44100, |
43 | 43 | 2, |
44 | - AUD_FMT_S16 | |
44 | + AUD_FMT_S16, | |
45 | + AUDIO_HOST_ENDIANNESS | |
45 | 46 | }, |
46 | 47 | "qemu.wav" |
47 | 48 | }; |
... | ... | @@ -131,6 +132,11 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as) |
131 | 132 | case AUD_FMT_U16: |
132 | 133 | bits16 = 1; |
133 | 134 | break; |
135 | + | |
136 | + case AUD_FMT_S32: | |
137 | + case AUD_FMT_U32: | |
138 | + dolog ("WAVE files can not handle 32bit formats\n"); | |
139 | + return -1; | |
134 | 140 | } |
135 | 141 | |
136 | 142 | hdr[34] = bits16 ? 0x10 : 0x08; | ... | ... |
audio/wavcapture.c
... | ... | @@ -37,15 +37,15 @@ static void wav_destroy (void *opaque) |
37 | 37 | if (wav->f) { |
38 | 38 | le_store (rlen, rifflen, 4); |
39 | 39 | le_store (dlen, datalen, 4); |
40 | - | |
40 | + | |
41 | 41 | qemu_fseek (wav->f, 4, SEEK_SET); |
42 | 42 | qemu_put_buffer (wav->f, rlen, 4); |
43 | - | |
43 | + | |
44 | 44 | qemu_fseek (wav->f, 32, SEEK_CUR); |
45 | 45 | qemu_put_buffer (wav->f, dlen, 4); |
46 | 46 | qemu_fclose (wav->f); |
47 | 47 | } |
48 | - | |
48 | + | |
49 | 49 | qemu_free (wav->path); |
50 | 50 | } |
51 | 51 | ... | ... |