blob: 5863803584baa2bc02d3b51331e9d47ade480866 [file] [log] [blame]
Peter Maydell6086a562016-01-18 17:33:52 +00001#include "qemu/osdep.h"
pbrook87ecb682007-11-17 17:14:51 +00002#include "hw/hw.h"
Paolo Bonzini83c90892012-12-17 18:19:49 +01003#include "monitor/monitor.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;
Juan Quintelab04df2a2011-09-20 15:16:28 +020040 Monitor *mon = cur_mon;
bellard8ead62c2006-07-04 16:51:32 +000041
bellarde84a4fe2006-08-07 21:35:12 +000042 if (wav->f) {
43 le_store (rlen, rifflen, 4);
44 le_store (dlen, datalen, 4);
thsf941aa22007-02-17 22:19:29 +000045
Juan Quintelab04df2a2011-09-20 15:16:28 +020046 if (fseek (wav->f, 4, SEEK_SET)) {
47 monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n",
48 strerror (errno));
49 goto doclose;
50 }
51 if (fwrite (rlen, 4, 1, wav->f) != 1) {
52 monitor_printf (mon, "wav_destroy: rlen fwrite failed\nReason %s\n",
53 strerror (errno));
54 goto doclose;
55 }
56 if (fseek (wav->f, 32, SEEK_CUR)) {
57 monitor_printf (mon, "wav_destroy: dlen fseek failed\nReason %s\n",
58 strerror (errno));
59 goto doclose;
60 }
61 if (fwrite (dlen, 1, 4, wav->f) != 4) {
62 monitor_printf (mon, "wav_destroy: dlen fwrite failed\nReason %s\n",
63 strerror (errno));
64 goto doclose;
65 }
66 doclose:
67 if (fclose (wav->f)) {
Le Tan69e99502014-05-10 07:55:20 +080068 error_report("wav_destroy: fclose failed: %s", strerror(errno));
Juan Quintelab04df2a2011-09-20 15:16:28 +020069 }
bellard8ead62c2006-07-04 16:51:32 +000070 }
thsf941aa22007-02-17 22:19:29 +000071
Anthony Liguori7267c092011-08-20 22:09:37 -050072 g_free (wav->path);
bellard8ead62c2006-07-04 16:51:32 +000073}
74
bellardec36b692006-07-16 18:57:03 +000075static void wav_capture (void *opaque, void *buf, int size)
bellard8ead62c2006-07-04 16:51:32 +000076{
77 WAVState *wav = opaque;
78
Juan Quintelab04df2a2011-09-20 15:16:28 +020079 if (fwrite (buf, size, 1, wav->f) != 1) {
80 monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
81 strerror (errno));
82 }
bellard8ead62c2006-07-04 16:51:32 +000083 wav->bytes += size;
84}
85
bellardec36b692006-07-16 18:57:03 +000086static void wav_capture_destroy (void *opaque)
87{
88 WAVState *wav = opaque;
89
90 AUD_del_capture (wav->cap, wav);
Marc-André Lureau7bdfd902017-05-04 02:38:44 +040091 g_free (wav);
bellardec36b692006-07-16 18:57:03 +000092}
93
94static void wav_capture_info (void *opaque)
95{
96 WAVState *wav = opaque;
97 char *path = wav->path;
98
Juan Quintelab04df2a2011-09-20 15:16:28 +020099 monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
100 wav->freq, wav->bits, wav->nchannels,
101 path ? path : "<not available>", wav->bytes);
bellardec36b692006-07-16 18:57:03 +0000102}
103
104static struct capture_ops wav_capture_ops = {
105 .destroy = wav_capture_destroy,
106 .info = wav_capture_info
107};
108
109int wav_start_capture (CaptureState *s, const char *path, int freq,
110 int bits, int nchannels)
bellard8ead62c2006-07-04 16:51:32 +0000111{
aliguori376253e2009-03-05 23:01:23 +0000112 Monitor *mon = cur_mon;
bellard8ead62c2006-07-04 16:51:32 +0000113 WAVState *wav;
114 uint8_t hdr[] = {
115 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
116 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
117 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
118 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
119 };
malc1ea879e2008-12-03 22:48:44 +0000120 struct audsettings as;
bellard8ead62c2006-07-04 16:51:32 +0000121 struct audio_capture_ops ops;
bellardec36b692006-07-16 18:57:03 +0000122 int stereo, bits16, shift;
123 CaptureVoiceOut *cap;
bellard8ead62c2006-07-04 16:51:32 +0000124
bellardec36b692006-07-16 18:57:03 +0000125 if (bits != 8 && bits != 16) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200126 monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
bellardec36b692006-07-16 18:57:03 +0000127 return -1;
128 }
129
130 if (nchannels != 1 && nchannels != 2) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200131 monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
132 nchannels);
bellardec36b692006-07-16 18:57:03 +0000133 return -1;
134 }
135
136 stereo = nchannels == 2;
137 bits16 = bits == 16;
bellard8ead62c2006-07-04 16:51:32 +0000138
139 as.freq = freq;
140 as.nchannels = 1 << stereo;
141 as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
bellardd929eba2006-07-04 21:47:22 +0000142 as.endianness = 0;
bellard8ead62c2006-07-04 16:51:32 +0000143
bellardec36b692006-07-16 18:57:03 +0000144 ops.notify = wav_notify;
145 ops.capture = wav_capture;
146 ops.destroy = wav_destroy;
bellard8ead62c2006-07-04 16:51:32 +0000147
Anthony Liguori7267c092011-08-20 22:09:37 -0500148 wav = g_malloc0 (sizeof (*wav));
bellard8ead62c2006-07-04 16:51:32 +0000149
150 shift = bits16 + stereo;
151 hdr[34] = bits16 ? 0x10 : 0x08;
152
153 le_store (hdr + 22, as.nchannels, 2);
154 le_store (hdr + 24, freq, 4);
155 le_store (hdr + 28, freq << shift, 4);
156 le_store (hdr + 32, 1 << shift, 2);
157
Juan Quintelab04df2a2011-09-20 15:16:28 +0200158 wav->f = fopen (path, "wb");
bellard8ead62c2006-07-04 16:51:32 +0000159 if (!wav->f) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200160 monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
161 path, strerror (errno));
Anthony Liguori7267c092011-08-20 22:09:37 -0500162 g_free (wav);
bellardec36b692006-07-16 18:57:03 +0000163 return -1;
bellard8ead62c2006-07-04 16:51:32 +0000164 }
165
Anthony Liguori7267c092011-08-20 22:09:37 -0500166 wav->path = g_strdup (path);
bellardec36b692006-07-16 18:57:03 +0000167 wav->bits = bits;
168 wav->nchannels = nchannels;
169 wav->freq = freq;
170
Juan Quintelab04df2a2011-09-20 15:16:28 +0200171 if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
172 monitor_printf (mon, "Failed to write header\nReason: %s\n",
173 strerror (errno));
174 goto error_free;
175 }
bellardec36b692006-07-16 18:57:03 +0000176
malc1a7dafc2009-05-14 03:11:35 +0400177 cap = AUD_add_capture (&as, &ops, wav);
bellardec36b692006-07-16 18:57:03 +0000178 if (!cap) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200179 monitor_printf (mon, "Failed to add audio capture\n");
180 goto error_free;
bellardec36b692006-07-16 18:57:03 +0000181 }
182
183 wav->cap = cap;
184 s->opaque = wav;
185 s->ops = wav_capture_ops;
186 return 0;
Juan Quintelab04df2a2011-09-20 15:16:28 +0200187
188error_free:
189 g_free (wav->path);
190 if (fclose (wav->f)) {
191 monitor_printf (mon, "Failed to close wave file\nReason: %s\n",
192 strerror (errno));
193 }
194 g_free (wav);
195 return -1;
bellard8ead62c2006-07-04 16:51:32 +0000196}