blob: 8bfb9e765468936137a12e844ce578846f8b393d [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);
91}
92
93static void wav_capture_info (void *opaque)
94{
95 WAVState *wav = opaque;
96 char *path = wav->path;
97
Juan Quintelab04df2a2011-09-20 15:16:28 +020098 monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
99 wav->freq, wav->bits, wav->nchannels,
100 path ? path : "<not available>", wav->bytes);
bellardec36b692006-07-16 18:57:03 +0000101}
102
103static struct capture_ops wav_capture_ops = {
104 .destroy = wav_capture_destroy,
105 .info = wav_capture_info
106};
107
108int wav_start_capture (CaptureState *s, const char *path, int freq,
109 int bits, int nchannels)
bellard8ead62c2006-07-04 16:51:32 +0000110{
aliguori376253e2009-03-05 23:01:23 +0000111 Monitor *mon = cur_mon;
bellard8ead62c2006-07-04 16:51:32 +0000112 WAVState *wav;
113 uint8_t hdr[] = {
114 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
115 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
116 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
117 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
118 };
malc1ea879e2008-12-03 22:48:44 +0000119 struct audsettings as;
bellard8ead62c2006-07-04 16:51:32 +0000120 struct audio_capture_ops ops;
bellardec36b692006-07-16 18:57:03 +0000121 int stereo, bits16, shift;
122 CaptureVoiceOut *cap;
bellard8ead62c2006-07-04 16:51:32 +0000123
bellardec36b692006-07-16 18:57:03 +0000124 if (bits != 8 && bits != 16) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200125 monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
bellardec36b692006-07-16 18:57:03 +0000126 return -1;
127 }
128
129 if (nchannels != 1 && nchannels != 2) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200130 monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
131 nchannels);
bellardec36b692006-07-16 18:57:03 +0000132 return -1;
133 }
134
135 stereo = nchannels == 2;
136 bits16 = bits == 16;
bellard8ead62c2006-07-04 16:51:32 +0000137
138 as.freq = freq;
139 as.nchannels = 1 << stereo;
140 as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
bellardd929eba2006-07-04 21:47:22 +0000141 as.endianness = 0;
bellard8ead62c2006-07-04 16:51:32 +0000142
bellardec36b692006-07-16 18:57:03 +0000143 ops.notify = wav_notify;
144 ops.capture = wav_capture;
145 ops.destroy = wav_destroy;
bellard8ead62c2006-07-04 16:51:32 +0000146
Anthony Liguori7267c092011-08-20 22:09:37 -0500147 wav = g_malloc0 (sizeof (*wav));
bellard8ead62c2006-07-04 16:51:32 +0000148
149 shift = bits16 + stereo;
150 hdr[34] = bits16 ? 0x10 : 0x08;
151
152 le_store (hdr + 22, as.nchannels, 2);
153 le_store (hdr + 24, freq, 4);
154 le_store (hdr + 28, freq << shift, 4);
155 le_store (hdr + 32, 1 << shift, 2);
156
Juan Quintelab04df2a2011-09-20 15:16:28 +0200157 wav->f = fopen (path, "wb");
bellard8ead62c2006-07-04 16:51:32 +0000158 if (!wav->f) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200159 monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
160 path, strerror (errno));
Anthony Liguori7267c092011-08-20 22:09:37 -0500161 g_free (wav);
bellardec36b692006-07-16 18:57:03 +0000162 return -1;
bellard8ead62c2006-07-04 16:51:32 +0000163 }
164
Anthony Liguori7267c092011-08-20 22:09:37 -0500165 wav->path = g_strdup (path);
bellardec36b692006-07-16 18:57:03 +0000166 wav->bits = bits;
167 wav->nchannels = nchannels;
168 wav->freq = freq;
169
Juan Quintelab04df2a2011-09-20 15:16:28 +0200170 if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
171 monitor_printf (mon, "Failed to write header\nReason: %s\n",
172 strerror (errno));
173 goto error_free;
174 }
bellardec36b692006-07-16 18:57:03 +0000175
malc1a7dafc2009-05-14 03:11:35 +0400176 cap = AUD_add_capture (&as, &ops, wav);
bellardec36b692006-07-16 18:57:03 +0000177 if (!cap) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200178 monitor_printf (mon, "Failed to add audio capture\n");
179 goto error_free;
bellardec36b692006-07-16 18:57:03 +0000180 }
181
182 wav->cap = cap;
183 s->opaque = wav;
184 s->ops = wav_capture_ops;
185 return 0;
Juan Quintelab04df2a2011-09-20 15:16:28 +0200186
187error_free:
188 g_free (wav->path);
189 if (fclose (wav->f)) {
190 monitor_printf (mon, "Failed to close wave file\nReason: %s\n",
191 strerror (errno));
192 }
193 g_free (wav);
194 return -1;
bellard8ead62c2006-07-04 16:51:32 +0000195}