blob: c60286e1628bc25ae7d1d329d455bb6e06e78e02 [file] [log] [blame]
Peter Maydell6086a562016-01-18 17:33:52 +00001#include "qemu/osdep.h"
Kevin Wolf947e4742020-10-05 17:58:44 +02002#include "qemu/qemu-print.h"
Markus Armbrustere688df62018-02-01 12:18:31 +01003#include "qapi/error.h"
Markus Armbrusterd49b6832015-03-17 18:29:20 +01004#include "qemu/error-report.h"
pbrook87ecb682007-11-17 17:14:51 +00005#include "audio.h"
bellard8ead62c2006-07-04 16:51:32 +00006
7typedef struct {
Juan Quintelab04df2a2011-09-20 15:16:28 +02008 FILE *f;
bellard8ead62c2006-07-04 16:51:32 +00009 int bytes;
bellardec36b692006-07-16 18:57:03 +000010 char *path;
11 int freq;
12 int bits;
13 int nchannels;
14 CaptureVoiceOut *cap;
bellard8ead62c2006-07-04 16:51:32 +000015} WAVState;
16
17/* VICE code: Store number as little endian. */
18static void le_store (uint8_t *buf, uint32_t val, int len)
19{
20 int i;
21 for (i = 0; i < len; i++) {
22 buf[i] = (uint8_t) (val & 0xff);
23 val >>= 8;
24 }
25}
26
bellardec36b692006-07-16 18:57:03 +000027static void wav_notify (void *opaque, audcnotification_e cmd)
28{
29 (void) opaque;
30 (void) cmd;
31}
32
33static void wav_destroy (void *opaque)
bellard8ead62c2006-07-04 16:51:32 +000034{
35 WAVState *wav = opaque;
bellardec36b692006-07-16 18:57:03 +000036 uint8_t rlen[4];
37 uint8_t dlen[4];
38 uint32_t datalen = wav->bytes;
39 uint32_t rifflen = datalen + 36;
bellard8ead62c2006-07-04 16:51:32 +000040
bellarde84a4fe2006-08-07 21:35:12 +000041 if (wav->f) {
42 le_store (rlen, rifflen, 4);
43 le_store (dlen, datalen, 4);
thsf941aa22007-02-17 22:19:29 +000044
Juan Quintelab04df2a2011-09-20 15:16:28 +020045 if (fseek (wav->f, 4, SEEK_SET)) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +000046 error_report("wav_destroy: rlen fseek failed: %s",
47 strerror(errno));
Juan Quintelab04df2a2011-09-20 15:16:28 +020048 goto doclose;
49 }
50 if (fwrite (rlen, 4, 1, wav->f) != 1) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +000051 error_report("wav_destroy: rlen fwrite failed: %s",
52 strerror(errno));
Juan Quintelab04df2a2011-09-20 15:16:28 +020053 goto doclose;
54 }
55 if (fseek (wav->f, 32, SEEK_CUR)) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +000056 error_report("wav_destroy: dlen fseek failed: %s",
57 strerror(errno));
Juan Quintelab04df2a2011-09-20 15:16:28 +020058 goto doclose;
59 }
60 if (fwrite (dlen, 1, 4, wav->f) != 4) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +000061 error_report("wav_destroy: dlen fwrite failed: %s",
62 strerror(errno));
Juan Quintelab04df2a2011-09-20 15:16:28 +020063 goto doclose;
64 }
65 doclose:
66 if (fclose (wav->f)) {
Le Tan69e99502014-05-10 07:55:20 +080067 error_report("wav_destroy: fclose failed: %s", strerror(errno));
Juan Quintelab04df2a2011-09-20 15:16:28 +020068 }
bellard8ead62c2006-07-04 16:51:32 +000069 }
thsf941aa22007-02-17 22:19:29 +000070
Anthony Liguori7267c092011-08-20 22:09:37 -050071 g_free (wav->path);
bellard8ead62c2006-07-04 16:51:32 +000072}
73
Philippe Mathieu-Daudé57a878e2020-05-05 15:25:58 +020074static void wav_capture(void *opaque, const void *buf, int size)
bellard8ead62c2006-07-04 16:51:32 +000075{
76 WAVState *wav = opaque;
77
Juan Quintelab04df2a2011-09-20 15:16:28 +020078 if (fwrite (buf, size, 1, wav->f) != 1) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +000079 error_report("wav_capture: fwrite error: %s", strerror(errno));
Juan Quintelab04df2a2011-09-20 15:16:28 +020080 }
bellard8ead62c2006-07-04 16:51:32 +000081 wav->bytes += size;
82}
83
bellardec36b692006-07-16 18:57:03 +000084static void wav_capture_destroy (void *opaque)
85{
86 WAVState *wav = opaque;
87
88 AUD_del_capture (wav->cap, wav);
Marc-André Lureau7bdfd902017-05-04 02:38:44 +040089 g_free (wav);
bellardec36b692006-07-16 18:57:03 +000090}
91
92static void wav_capture_info (void *opaque)
93{
94 WAVState *wav = opaque;
95 char *path = wav->path;
96
Kevin Wolf947e4742020-10-05 17:58:44 +020097 qemu_printf("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
98 wav->freq, wav->bits, wav->nchannels,
99 path ? path : "<not available>", wav->bytes);
bellardec36b692006-07-16 18:57:03 +0000100}
101
102static struct capture_ops wav_capture_ops = {
103 .destroy = wav_capture_destroy,
104 .info = wav_capture_info
105};
106
Kővágó, Zoltánecd97e92019-08-19 01:06:47 +0200107int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
108 int freq, int bits, int nchannels)
bellard8ead62c2006-07-04 16:51:32 +0000109{
110 WAVState *wav;
111 uint8_t hdr[] = {
112 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
113 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
114 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
115 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
116 };
malc1ea879e2008-12-03 22:48:44 +0000117 struct audsettings as;
bellard8ead62c2006-07-04 16:51:32 +0000118 struct audio_capture_ops ops;
bellardec36b692006-07-16 18:57:03 +0000119 int stereo, bits16, shift;
120 CaptureVoiceOut *cap;
bellard8ead62c2006-07-04 16:51:32 +0000121
bellardec36b692006-07-16 18:57:03 +0000122 if (bits != 8 && bits != 16) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +0000123 error_report("incorrect bit count %d, must be 8 or 16", bits);
bellardec36b692006-07-16 18:57:03 +0000124 return -1;
125 }
126
127 if (nchannels != 1 && nchannels != 2) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +0000128 error_report("incorrect channel count %d, must be 1 or 2",
129 nchannels);
bellardec36b692006-07-16 18:57:03 +0000130 return -1;
131 }
132
133 stereo = nchannels == 2;
134 bits16 = bits == 16;
bellard8ead62c2006-07-04 16:51:32 +0000135
136 as.freq = freq;
137 as.nchannels = 1 << stereo;
Kővágó, Zoltán85bc5852019-03-08 23:34:13 +0100138 as.fmt = bits16 ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8;
bellardd929eba2006-07-04 21:47:22 +0000139 as.endianness = 0;
bellard8ead62c2006-07-04 16:51:32 +0000140
bellardec36b692006-07-16 18:57:03 +0000141 ops.notify = wav_notify;
142 ops.capture = wav_capture;
143 ops.destroy = wav_destroy;
bellard8ead62c2006-07-04 16:51:32 +0000144
Anthony Liguori7267c092011-08-20 22:09:37 -0500145 wav = g_malloc0 (sizeof (*wav));
bellard8ead62c2006-07-04 16:51:32 +0000146
147 shift = bits16 + stereo;
148 hdr[34] = bits16 ? 0x10 : 0x08;
149
150 le_store (hdr + 22, as.nchannels, 2);
151 le_store (hdr + 24, freq, 4);
152 le_store (hdr + 28, freq << shift, 4);
153 le_store (hdr + 32, 1 << shift, 2);
154
Juan Quintelab04df2a2011-09-20 15:16:28 +0200155 wav->f = fopen (path, "wb");
bellard8ead62c2006-07-04 16:51:32 +0000156 if (!wav->f) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +0000157 error_report("Failed to open wave file `%s': %s",
158 path, strerror(errno));
Anthony Liguori7267c092011-08-20 22:09:37 -0500159 g_free (wav);
bellardec36b692006-07-16 18:57:03 +0000160 return -1;
bellard8ead62c2006-07-04 16:51:32 +0000161 }
162
Anthony Liguori7267c092011-08-20 22:09:37 -0500163 wav->path = g_strdup (path);
bellardec36b692006-07-16 18:57:03 +0000164 wav->bits = bits;
165 wav->nchannels = nchannels;
166 wav->freq = freq;
167
Juan Quintelab04df2a2011-09-20 15:16:28 +0200168 if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +0000169 error_report("Failed to write header: %s", strerror(errno));
Juan Quintelab04df2a2011-09-20 15:16:28 +0200170 goto error_free;
171 }
bellardec36b692006-07-16 18:57:03 +0000172
Kővágó, Zoltánecd97e92019-08-19 01:06:47 +0200173 cap = AUD_add_capture(state, &as, &ops, wav);
bellardec36b692006-07-16 18:57:03 +0000174 if (!cap) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +0000175 error_report("Failed to add audio capture");
Juan Quintelab04df2a2011-09-20 15:16:28 +0200176 goto error_free;
bellardec36b692006-07-16 18:57:03 +0000177 }
178
179 wav->cap = cap;
180 s->opaque = wav;
181 s->ops = wav_capture_ops;
182 return 0;
Juan Quintelab04df2a2011-09-20 15:16:28 +0200183
184error_free:
185 g_free (wav->path);
186 if (fclose (wav->f)) {
Dr. David Alan Gilbert8beaac12017-03-20 17:38:40 +0000187 error_report("Failed to close wave file: %s", strerror(errno));
Juan Quintelab04df2a2011-09-20 15:16:28 +0200188 }
189 g_free (wav);
190 return -1;
bellard8ead62c2006-07-04 16:51:32 +0000191}