1 #include "qemu/osdep.h" 2 #include "hw/hw.h" 3 #include "monitor/monitor.h" 4 #include "qapi/error.h" 5 #include "qemu/error-report.h" 6 #include "audio.h" 7 8 typedef struct { 9 FILE *f; 10 int bytes; 11 char *path; 12 int freq; 13 int bits; 14 int nchannels; 15 CaptureVoiceOut *cap; 16 } WAVState; 17 18 /* VICE code: Store number as little endian. */ 19 static void le_store (uint8_t *buf, uint32_t val, int len) 20 { 21 int i; 22 for (i = 0; i < len; i++) { 23 buf[i] = (uint8_t) (val & 0xff); 24 val >>= 8; 25 } 26 } 27 28 static void wav_notify (void *opaque, audcnotification_e cmd) 29 { 30 (void) opaque; 31 (void) cmd; 32 } 33 34 static void wav_destroy (void *opaque) 35 { 36 WAVState *wav = opaque; 37 uint8_t rlen[4]; 38 uint8_t dlen[4]; 39 uint32_t datalen = wav->bytes; 40 uint32_t rifflen = datalen + 36; 41 42 if (wav->f) { 43 le_store (rlen, rifflen, 4); 44 le_store (dlen, datalen, 4); 45 46 if (fseek (wav->f, 4, SEEK_SET)) { 47 error_report("wav_destroy: rlen fseek failed: %s", 48 strerror(errno)); 49 goto doclose; 50 } 51 if (fwrite (rlen, 4, 1, wav->f) != 1) { 52 error_report("wav_destroy: rlen fwrite failed: %s", 53 strerror(errno)); 54 goto doclose; 55 } 56 if (fseek (wav->f, 32, SEEK_CUR)) { 57 error_report("wav_destroy: dlen fseek failed: %s", 58 strerror(errno)); 59 goto doclose; 60 } 61 if (fwrite (dlen, 1, 4, wav->f) != 4) { 62 error_report("wav_destroy: dlen fwrite failed: %s", 63 strerror(errno)); 64 goto doclose; 65 } 66 doclose: 67 if (fclose (wav->f)) { 68 error_report("wav_destroy: fclose failed: %s", strerror(errno)); 69 } 70 } 71 72 g_free (wav->path); 73 } 74 75 static void wav_capture (void *opaque, void *buf, int size) 76 { 77 WAVState *wav = opaque; 78 79 if (fwrite (buf, size, 1, wav->f) != 1) { 80 error_report("wav_capture: fwrite error: %s", strerror(errno)); 81 } 82 wav->bytes += size; 83 } 84 85 static void wav_capture_destroy (void *opaque) 86 { 87 WAVState *wav = opaque; 88 89 AUD_del_capture (wav->cap, wav); 90 g_free (wav); 91 } 92 93 static void wav_capture_info (void *opaque) 94 { 95 WAVState *wav = opaque; 96 char *path = wav->path; 97 98 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); 101 } 102 103 static struct capture_ops wav_capture_ops = { 104 .destroy = wav_capture_destroy, 105 .info = wav_capture_info 106 }; 107 108 int wav_start_capture (CaptureState *s, const char *path, int freq, 109 int bits, int nchannels) 110 { 111 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 }; 118 struct audsettings as; 119 struct audio_capture_ops ops; 120 int stereo, bits16, shift; 121 CaptureVoiceOut *cap; 122 123 if (bits != 8 && bits != 16) { 124 error_report("incorrect bit count %d, must be 8 or 16", bits); 125 return -1; 126 } 127 128 if (nchannels != 1 && nchannels != 2) { 129 error_report("incorrect channel count %d, must be 1 or 2", 130 nchannels); 131 return -1; 132 } 133 134 stereo = nchannels == 2; 135 bits16 = bits == 16; 136 137 as.freq = freq; 138 as.nchannels = 1 << stereo; 139 as.fmt = bits16 ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8; 140 as.endianness = 0; 141 142 ops.notify = wav_notify; 143 ops.capture = wav_capture; 144 ops.destroy = wav_destroy; 145 146 wav = g_malloc0 (sizeof (*wav)); 147 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 156 wav->f = fopen (path, "wb"); 157 if (!wav->f) { 158 error_report("Failed to open wave file `%s': %s", 159 path, strerror(errno)); 160 g_free (wav); 161 return -1; 162 } 163 164 wav->path = g_strdup (path); 165 wav->bits = bits; 166 wav->nchannels = nchannels; 167 wav->freq = freq; 168 169 if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) { 170 error_report("Failed to write header: %s", strerror(errno)); 171 goto error_free; 172 } 173 174 cap = AUD_add_capture (&as, &ops, wav); 175 if (!cap) { 176 error_report("Failed to add audio capture"); 177 goto error_free; 178 } 179 180 wav->cap = cap; 181 s->opaque = wav; 182 s->ops = wav_capture_ops; 183 return 0; 184 185 error_free: 186 g_free (wav->path); 187 if (fclose (wav->f)) { 188 error_report("Failed to close wave file: %s", strerror(errno)); 189 } 190 g_free (wav); 191 return -1; 192 } 193