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}
  92
  93static void wav_capture_info (void *opaque)
  94{
  95    WAVState *wav = opaque;
  96    char *path = wav->path;
  97
  98    monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
  99                    wav->freq, wav->bits, wav->nchannels,
 100                    path ? path : "<not available>", wav->bytes);
 101}
 102
 103static struct capture_ops wav_capture_ops = {
 104    .destroy = wav_capture_destroy,
 105    .info = wav_capture_info
 106};
 107
 108int wav_start_capture (CaptureState *s, const char *path, int freq,
 109                       int bits, int nchannels)
 110{
 111    Monitor *mon = cur_mon;
 112    WAVState *wav;
 113    uint8_t hdr[] = {
 114        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
 115        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
 116        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
 117        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
 118    };
 119    struct audsettings as;
 120    struct audio_capture_ops ops;
 121    int stereo, bits16, shift;
 122    CaptureVoiceOut *cap;
 123
 124    if (bits != 8 && bits != 16) {
 125        monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
 126        return -1;
 127    }
 128
 129    if (nchannels != 1 && nchannels != 2) {
 130        monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
 131                        nchannels);
 132        return -1;
 133    }
 134
 135    stereo = nchannels == 2;
 136    bits16 = bits == 16;
 137
 138    as.freq = freq;
 139    as.nchannels = 1 << stereo;
 140    as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
 141    as.endianness = 0;
 142
 143    ops.notify = wav_notify;
 144    ops.capture = wav_capture;
 145    ops.destroy = wav_destroy;
 146
 147    wav = g_malloc0 (sizeof (*wav));
 148
 149    shift = bits16 + stereo;
 150    hdr[34] = bits16 ? 0x10 : 0x08;
 151
 152    le_store (hdr + 22, as.nchannels, 2);
 153    le_store (hdr + 24, freq, 4);
 154    le_store (hdr + 28, freq << shift, 4);
 155    le_store (hdr + 32, 1 << shift, 2);
 156
 157    wav->f = fopen (path, "wb");
 158    if (!wav->f) {
 159        monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
 160                        path, strerror (errno));
 161        g_free (wav);
 162        return -1;
 163    }
 164
 165    wav->path = g_strdup (path);
 166    wav->bits = bits;
 167    wav->nchannels = nchannels;
 168    wav->freq = freq;
 169
 170    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
 171        monitor_printf (mon, "Failed to write header\nReason: %s\n",
 172                        strerror (errno));
 173        goto error_free;
 174    }
 175
 176    cap = AUD_add_capture (&as, &ops, wav);
 177    if (!cap) {
 178        monitor_printf (mon, "Failed to add audio capture\n");
 179        goto error_free;
 180    }
 181
 182    wav->cap = cap;
 183    s->opaque = wav;
 184    s->ops = wav_capture_ops;
 185    return 0;
 186
 187error_free:
 188    g_free (wav->path);
 189    if (fclose (wav->f)) {
 190        monitor_printf (mon, "Failed to close wave file\nReason: %s\n",
 191                        strerror (errno));
 192    }
 193    g_free (wav);
 194    return -1;
 195}
 196