15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "hw/hw.h" 25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "monitor.h" 35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "audio.h" 48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct { 68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project QEMUFile *f; 78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int bytes; 88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *path; 98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int freq; 108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int bits; 118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int nchannels; 128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project CaptureVoiceOut *cap; 138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} WAVState; 148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* VICE code: Store number as little endian. */ 168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void le_store (uint8_t *buf, uint32_t val, int len) 178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 0; i < len; i++) { 208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project buf[i] = (uint8_t) (val & 0xff); 218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project val >>= 8; 228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void wav_notify (void *opaque, audcnotification_e cmd) 268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (void) opaque; 288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (void) cmd; 298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void wav_destroy (void *opaque) 328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project WAVState *wav = opaque; 348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t rlen[4]; 358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t dlen[4]; 368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t datalen = wav->bytes; 378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t rifflen = datalen + 36; 388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (wav->f) { 405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le_store (rlen, rifflen, 4); 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le_store (dlen, datalen, 4); 428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fseek (wav->f, 4, SEEK_SET); 445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer (wav->f, rlen, 4); 458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fseek (wav->f, 32, SEEK_CUR); 475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer (wav->f, dlen, 4); 485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fclose (wav->f); 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free (wav->path); 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void wav_capture (void *opaque, void *buf, int size) 558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project WAVState *wav = opaque; 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_buffer (wav->f, buf, size); 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project wav->bytes += size; 608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void wav_capture_destroy (void *opaque) 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project WAVState *wav = opaque; 658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project AUD_del_capture (wav->cap, wav); 678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void wav_capture_info (void *opaque) 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project WAVState *wav = opaque; 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *path = wav->path; 738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n", 755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner wav->freq, wav->bits, wav->nchannels, 765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner path ? path : "<not available>", wav->bytes); 778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic struct capture_ops wav_capture_ops = { 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project .destroy = wav_capture_destroy, 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project .info = wav_capture_info 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint wav_start_capture (CaptureState *s, const char *path, int freq, 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int bits, int nchannels) 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner Monitor *mon = cur_mon; 888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project WAVState *wav; 898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t hdr[] = { 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project }; 955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct audsettings as; 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project struct audio_capture_ops ops; 978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int stereo, bits16, shift; 988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project CaptureVoiceOut *cap; 998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bits != 8 && bits != 16) { 1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "incorrect bit count %d, must be 8 or 16\n", bits); 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (nchannels != 1 && nchannels != 2) { 1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "incorrect channel count %d, must be 1 or 2\n", 1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nchannels); 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project stereo = nchannels == 2; 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bits16 = bits == 16; 1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project as.freq = freq; 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project as.nchannels = 1 << stereo; 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; 1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project as.endianness = 0; 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ops.notify = wav_notify; 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ops.capture = wav_capture; 1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ops.destroy = wav_destroy; 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project wav = qemu_mallocz (sizeof (*wav)); 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project shift = bits16 + stereo; 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project hdr[34] = bits16 ? 0x10 : 0x08; 1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project le_store (hdr + 22, as.nchannels, 2); 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project le_store (hdr + 24, freq, 4); 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project le_store (hdr + 28, freq << shift, 4); 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project le_store (hdr + 32, 1 << shift, 2); 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project wav->f = qemu_fopen (path, "wb"); 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!wav->f) { 1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Failed to open wave file `%s'\nReason: %s\n", 1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner path, strerror (errno)); 1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free (wav); 1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project wav->path = qemu_strdup (path); 1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project wav->bits = bits; 1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project wav->nchannels = nchannels; 1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project wav->freq = freq; 1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_put_buffer (wav->f, hdr, sizeof (hdr)); 1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner cap = AUD_add_capture (&as, &ops, wav); 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!cap) { 1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Failed to add audio capture\n"); 1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free (wav->path); 1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_fclose (wav->f); 1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free (wav); 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project wav->cap = cap; 1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->opaque = wav; 1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->ops = wav_capture_ops; 1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 162