10e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner#include <stdio.h> 26af6765e2f3bc930d0dce21d752bea570a1b1362David 'Digit' Turner#include "monitor/monitor.h" 35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "audio.h" 48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct { 60e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner FILE *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 430e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner fseek (wav->f, 4, SEEK_SET); 440e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner fwrite(rlen, 4, 1, wav->f); 458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 460e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner fseek (wav->f, 32, SEEK_CUR); 470e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner fwrite(dlen, 4, 1, wav->f); 480e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner fclose (wav->f); 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 51aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_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 580e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner fwrite(buf, size, 1, wav->f); 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 123aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner wav = g_malloc0 (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 1330e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner wav->f = 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)); 137aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free (wav); 1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 141aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner wav->path = g_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 1460e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner fwrite(hdr, sizeof(hdr), 1, wav->f); 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"); 151aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free (wav->path); 1520e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner fclose (wav->f); 153aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_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