qemu/audio/wavcapture.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include "hw/hw.h"
   3#include "monitor/monitor.h"
   4#include "qemu/error-report.h"
   5#include "audio.h"
   6
   7typedef struct {
   8    FILE *f;
   9    int bytes;
  10    char *path;
  11    int freq;
  12    int bits;
  13    int nchannels;
  14    CaptureVoiceOut *cap;
  15} WAVState;
  16
  17/* VICE code: Store number as little endian. */
  18static void le_store (uint8_t *buf, uint32_t val, int len)
  19{
  20    int i;
  21    for (i = 0; i < len; i++) {
  22        buf[i] = (uint8_t) (val & 0xff);
  23        val >>= 8;
  24    }
  25}
  26
  27static void wav_notify (void *opaque, audcnotification_e cmd)
  28{
  29    (void) opaque;
  30    (void) cmd;
  31}
  32
  33static void wav_destroy (void *opaque)
  34{
  35    WAVState *wav = opaque;
  36    uint8_t rlen[4];
  37    uint8_t dlen[4];
  38    uint32_t datalen = wav->bytes;
  39    uint32_t rifflen = datalen + 36;
  40    Monitor *mon = cur_mon;
  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            monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n",
  48                            strerror (errno));
  49            goto doclose;
  50        }
  51        if (fwrite (rlen, 4, 1, wav->f) != 1) {
  52            monitor_printf (mon, "wav_destroy: rlen fwrite failed\nReason %s\n",
  53                            strerror (errno));
  54            goto doclose;
  55        }
  56        if (fseek (wav->f, 32, SEEK_CUR)) {
  57            monitor_printf (mon, "wav_destroy: dlen fseek failed\nReason %s\n",
  58                            strerror (errno));
  59            goto doclose;
  60        }
  61        if (fwrite (dlen, 1, 4, wav->f) != 4) {
  62            monitor_printf (mon, "wav_destroy: dlen fwrite failed\nReason %s\n",
  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
  75static 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        monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
  81                        strerror (errno));
  82    }
  83    wav->bytes += size;
  84}
  85
  86static void wav_capture_destroy (void *opaque)
  87{
  88    WAVState *wav = opaque;
  89
  90    AUD_del_capture (wav->cap, wav);
  91    g_free (wav);
  92}
  93
  94static void wav_capture_info (void *opaque)
  95{
  96    WAVState *wav = opaque;
  97    char *path = wav->path;
  98
  99    monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
 100                    wav->freq, wav->bits, wav->nchannels,
 101                    path ? path : "<not available>", wav->bytes);
 102}
 103
 104static struct capture_ops wav_capture_ops = {
 105    .destroy = wav_capture_destroy,
 106    .info = wav_capture_info
 107};
 108
 109int wav_start_capture (CaptureState *s, const char *path, int freq,
 110                       int bits, int nchannels)
 111{
 112    Monitor *mon = cur_mon;
 113    WAVState *wav;
 114    uint8_t hdr[] = {
 115        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
 116        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
 117        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
 118        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
 119    };
 120    struct audsettings as;
 121    struct audio_capture_ops ops;
 122    int stereo, bits16, shift;
 123    CaptureVoiceOut *cap;
 124
 125    if (bits != 8 && bits != 16) {
 126        monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
 127        return -1;
 128    }
 129
 130    if (nchannels != 1 && nchannels != 2) {
 131        monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
 132                        nchannels);
 133        return -1;
 134    }
 135
 136    stereo = nchannels == 2;
 137    bits16 = bits == 16;
 138
 139    as.freq = freq;
 140    as.nchannels = 1 << stereo;
 141    as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
 142    as.endianness = 0;
 143
 144    ops.notify = wav_notify;
 145    ops.capture = wav_capture;
 146    ops.destroy = wav_destroy;
 147
 148    wav = g_malloc0 (sizeof (*wav));
 149
 150    shift = bits16 + stereo;
 151    hdr[34] = bits16 ? 0x10 : 0x08;
 152
 153    le_store (hdr + 22, as.nchannels, 2);
 154    le_store (hdr + 24, freq, 4);
 155    le_store (hdr + 28, freq << shift, 4);
 156    le_store (hdr + 32, 1 << shift, 2);
 157
 158    wav->f = fopen (path, "wb");
 159    if (!wav->f) {
 160        monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
 161                        path, strerror (errno));
 162        g_free (wav);
 163        return -1;
 164    }
 165
 166    wav->path = g_strdup (path);
 167    wav->bits = bits;
 168    wav->nchannels = nchannels;
 169    wav->freq = freq;
 170
 171    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
 172        monitor_printf (mon, "Failed to write header\nReason: %s\n",
 173                        strerror (errno));
 174        goto error_free;
 175    }
 176
 177    cap = AUD_add_capture (&as, &ops, wav);
 178    if (!cap) {
 179        monitor_printf (mon, "Failed to add audio capture\n");
 180        goto error_free;
 181    }
 182
 183    wav->cap = cap;
 184    s->opaque = wav;
 185    s->ops = wav_capture_ops;
 186    return 0;
 187
 188error_free:
 189    g_free (wav->path);
 190    if (fclose (wav->f)) {
 191        monitor_printf (mon, "Failed to close wave file\nReason: %s\n",
 192                        strerror (errno));
 193    }
 194    g_free (wav);
 195    return -1;
 196}
 197