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