qemu/audio/wavcapture.c
<<
>>
Prefs
   1#include "hw/hw.h"
   2#include "monitor/monitor.h"
   3#include "audio.h"
   4
   5typedef struct {
   6    FILE *f;
   7    int bytes;
   8    char *path;
   9    int freq;
  10    int bits;
  11    int nchannels;
  12    CaptureVoiceOut *cap;
  13} 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
  25static void wav_notify (void *opaque, audcnotification_e cmd)
  26{
  27    (void) opaque;
  28    (void) cmd;
  29}
  30
  31static void wav_destroy (void *opaque)
  32{
  33    WAVState *wav = opaque;
  34    uint8_t rlen[4];
  35    uint8_t dlen[4];
  36    uint32_t datalen = wav->bytes;
  37    uint32_t rifflen = datalen + 36;
  38    Monitor *mon = cur_mon;
  39
  40    if (wav->f) {
  41        le_store (rlen, rifflen, 4);
  42        le_store (dlen, datalen, 4);
  43
  44        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        }
  69    }
  70
  71    g_free (wav->path);
  72}
  73
  74static void wav_capture (void *opaque, void *buf, int size)
  75{
  76    WAVState *wav = opaque;
  77
  78    if (fwrite (buf, size, 1, wav->f) != 1) {
  79        monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
  80                        strerror (errno));
  81    }
  82    wav->bytes += size;
  83}
  84
  85static 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
  97    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);
 100}
 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)
 109{
 110    Monitor *mon = cur_mon;
 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        monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
 125        return -1;
 126    }
 127
 128    if (nchannels != 1 && nchannels != 2) {
 129        monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
 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 ? AUD_FMT_S16 : AUD_FMT_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        monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
 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        monitor_printf (mon, "Failed to write header\nReason: %s\n",
 171                        strerror (errno));
 172        goto error_free;
 173    }
 174
 175    cap = AUD_add_capture (&as, &ops, wav);
 176    if (!cap) {
 177        monitor_printf (mon, "Failed to add audio capture\n");
 178        goto error_free;
 179    }
 180
 181    wav->cap = cap;
 182    s->opaque = wav;
 183    s->ops = wav_capture_ops;
 184    return 0;
 185
 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;
 194}
 195