blob: 9d94623225b286e6cd3f5f8fefe8b9cca34f2908 [file] [log] [blame]
pbrook87ecb682007-11-17 17:14:51 +00001#include "hw/hw.h"
Paolo Bonzini83c90892012-12-17 18:19:49 +01002#include "monitor/monitor.h"
pbrook87ecb682007-11-17 17:14:51 +00003#include "audio.h"
bellard8ead62c2006-07-04 16:51:32 +00004
5typedef struct {
Juan Quintelab04df2a2011-09-20 15:16:28 +02006 FILE *f;
bellard8ead62c2006-07-04 16:51:32 +00007 int bytes;
bellardec36b692006-07-16 18:57:03 +00008 char *path;
9 int freq;
10 int bits;
11 int nchannels;
12 CaptureVoiceOut *cap;
bellard8ead62c2006-07-04 16:51:32 +000013} WAVState;
14
15/* VICE code: Store number as little endian. */
16static void le_store (uint8_t *buf, uint32_t val, int len)
17{
18 int i;
19 for (i = 0; i < len; i++) {
20 buf[i] = (uint8_t) (val & 0xff);
21 val >>= 8;
22 }
23}
24
bellardec36b692006-07-16 18:57:03 +000025static void wav_notify (void *opaque, audcnotification_e cmd)
26{
27 (void) opaque;
28 (void) cmd;
29}
30
31static void wav_destroy (void *opaque)
bellard8ead62c2006-07-04 16:51:32 +000032{
33 WAVState *wav = opaque;
bellardec36b692006-07-16 18:57:03 +000034 uint8_t rlen[4];
35 uint8_t dlen[4];
36 uint32_t datalen = wav->bytes;
37 uint32_t rifflen = datalen + 36;
Juan Quintelab04df2a2011-09-20 15:16:28 +020038 Monitor *mon = cur_mon;
bellard8ead62c2006-07-04 16:51:32 +000039
bellarde84a4fe2006-08-07 21:35:12 +000040 if (wav->f) {
41 le_store (rlen, rifflen, 4);
42 le_store (dlen, datalen, 4);
thsf941aa22007-02-17 22:19:29 +000043
Juan Quintelab04df2a2011-09-20 15:16:28 +020044 if (fseek (wav->f, 4, SEEK_SET)) {
45 monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n",
46 strerror (errno));
47 goto doclose;
48 }
49 if (fwrite (rlen, 4, 1, wav->f) != 1) {
50 monitor_printf (mon, "wav_destroy: rlen fwrite failed\nReason %s\n",
51 strerror (errno));
52 goto doclose;
53 }
54 if (fseek (wav->f, 32, SEEK_CUR)) {
55 monitor_printf (mon, "wav_destroy: dlen fseek failed\nReason %s\n",
56 strerror (errno));
57 goto doclose;
58 }
59 if (fwrite (dlen, 1, 4, wav->f) != 4) {
60 monitor_printf (mon, "wav_destroy: dlen fwrite failed\nReason %s\n",
61 strerror (errno));
62 goto doclose;
63 }
64 doclose:
65 if (fclose (wav->f)) {
66 fprintf (stderr, "wav_destroy: fclose failed: %s",
67 strerror (errno));
68 }
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
bellardec36b692006-07-16 18:57:03 +000074static void wav_capture (void *opaque, 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) {
79 monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
80 strerror (errno));
81 }
bellard8ead62c2006-07-04 16:51:32 +000082 wav->bytes += size;
83}
84
bellardec36b692006-07-16 18:57:03 +000085static void wav_capture_destroy (void *opaque)
86{
87 WAVState *wav = opaque;
88
89 AUD_del_capture (wav->cap, wav);
90}
91
92static void wav_capture_info (void *opaque)
93{
94 WAVState *wav = opaque;
95 char *path = wav->path;
96
Juan Quintelab04df2a2011-09-20 15:16:28 +020097 monitor_printf (cur_mon, "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
107int wav_start_capture (CaptureState *s, const char *path, int freq,
108 int bits, int nchannels)
bellard8ead62c2006-07-04 16:51:32 +0000109{
aliguori376253e2009-03-05 23:01:23 +0000110 Monitor *mon = cur_mon;
bellard8ead62c2006-07-04 16:51:32 +0000111 WAVState *wav;
112 uint8_t hdr[] = {
113 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
114 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
115 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
116 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
117 };
malc1ea879e2008-12-03 22:48:44 +0000118 struct audsettings as;
bellard8ead62c2006-07-04 16:51:32 +0000119 struct audio_capture_ops ops;
bellardec36b692006-07-16 18:57:03 +0000120 int stereo, bits16, shift;
121 CaptureVoiceOut *cap;
bellard8ead62c2006-07-04 16:51:32 +0000122
bellardec36b692006-07-16 18:57:03 +0000123 if (bits != 8 && bits != 16) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200124 monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
bellardec36b692006-07-16 18:57:03 +0000125 return -1;
126 }
127
128 if (nchannels != 1 && nchannels != 2) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200129 monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
130 nchannels);
bellardec36b692006-07-16 18:57:03 +0000131 return -1;
132 }
133
134 stereo = nchannels == 2;
135 bits16 = bits == 16;
bellard8ead62c2006-07-04 16:51:32 +0000136
137 as.freq = freq;
138 as.nchannels = 1 << stereo;
139 as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
bellardd929eba2006-07-04 21:47:22 +0000140 as.endianness = 0;
bellard8ead62c2006-07-04 16:51:32 +0000141
bellardec36b692006-07-16 18:57:03 +0000142 ops.notify = wav_notify;
143 ops.capture = wav_capture;
144 ops.destroy = wav_destroy;
bellard8ead62c2006-07-04 16:51:32 +0000145
Anthony Liguori7267c092011-08-20 22:09:37 -0500146 wav = g_malloc0 (sizeof (*wav));
bellard8ead62c2006-07-04 16:51:32 +0000147
148 shift = bits16 + stereo;
149 hdr[34] = bits16 ? 0x10 : 0x08;
150
151 le_store (hdr + 22, as.nchannels, 2);
152 le_store (hdr + 24, freq, 4);
153 le_store (hdr + 28, freq << shift, 4);
154 le_store (hdr + 32, 1 << shift, 2);
155
Juan Quintelab04df2a2011-09-20 15:16:28 +0200156 wav->f = fopen (path, "wb");
bellard8ead62c2006-07-04 16:51:32 +0000157 if (!wav->f) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200158 monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
159 path, strerror (errno));
Anthony Liguori7267c092011-08-20 22:09:37 -0500160 g_free (wav);
bellardec36b692006-07-16 18:57:03 +0000161 return -1;
bellard8ead62c2006-07-04 16:51:32 +0000162 }
163
Anthony Liguori7267c092011-08-20 22:09:37 -0500164 wav->path = g_strdup (path);
bellardec36b692006-07-16 18:57:03 +0000165 wav->bits = bits;
166 wav->nchannels = nchannels;
167 wav->freq = freq;
168
Juan Quintelab04df2a2011-09-20 15:16:28 +0200169 if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
170 monitor_printf (mon, "Failed to write header\nReason: %s\n",
171 strerror (errno));
172 goto error_free;
173 }
bellardec36b692006-07-16 18:57:03 +0000174
malc1a7dafc2009-05-14 03:11:35 +0400175 cap = AUD_add_capture (&as, &ops, wav);
bellardec36b692006-07-16 18:57:03 +0000176 if (!cap) {
Juan Quintelab04df2a2011-09-20 15:16:28 +0200177 monitor_printf (mon, "Failed to add audio capture\n");
178 goto error_free;
bellardec36b692006-07-16 18:57:03 +0000179 }
180
181 wav->cap = cap;
182 s->opaque = wav;
183 s->ops = wav_capture_ops;
184 return 0;
Juan Quintelab04df2a2011-09-20 15:16:28 +0200185
186error_free:
187 g_free (wav->path);
188 if (fclose (wav->f)) {
189 monitor_printf (mon, "Failed to close wave file\nReason: %s\n",
190 strerror (errno));
191 }
192 g_free (wav);
193 return -1;
bellard8ead62c2006-07-04 16:51:32 +0000194}