qemu/audio/wavcapture.c
<<
>>
Prefs
   1#include "hw/hw.h"
   2#include "console.h"
   3#include "audio.h"
   4
   5typedef struct {
   6    QEMUFile *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
  39    if (wav->f) {
  40        le_store (rlen, rifflen, 4);
  41        le_store (dlen, datalen, 4);
  42
  43        qemu_fseek (wav->f, 4, SEEK_SET);
  44        qemu_put_buffer (wav->f, rlen, 4);
  45
  46        qemu_fseek (wav->f, 32, SEEK_CUR);
  47        qemu_put_buffer (wav->f, dlen, 4);
  48        qemu_fclose (wav->f);
  49    }
  50
  51    qemu_free (wav->path);
  52}
  53
  54static void wav_capture (void *opaque, void *buf, int size)
  55{
  56    WAVState *wav = opaque;
  57
  58    qemu_put_buffer (wav->f, buf, size);
  59    wav->bytes += size;
  60}
  61
  62static void wav_capture_destroy (void *opaque)
  63{
  64    WAVState *wav = opaque;
  65
  66    AUD_del_capture (wav->cap, wav);
  67}
  68
  69static void wav_capture_info (void *opaque)
  70{
  71    WAVState *wav = opaque;
  72    char *path = wav->path;
  73
  74    term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
  75                 wav->freq, wav->bits, wav->nchannels,
  76                 path ? path : "<not available>", wav->bytes);
  77}
  78
  79static struct capture_ops wav_capture_ops = {
  80    .destroy = wav_capture_destroy,
  81    .info = wav_capture_info
  82};
  83
  84int wav_start_capture (CaptureState *s, const char *path, int freq,
  85                       int bits, int nchannels)
  86{
  87    WAVState *wav;
  88    uint8_t hdr[] = {
  89        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
  90        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
  91        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
  92        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
  93    };
  94    struct audsettings as;
  95    struct audio_capture_ops ops;
  96    int stereo, bits16, shift;
  97    CaptureVoiceOut *cap;
  98
  99    if (bits != 8 && bits != 16) {
 100        term_printf ("incorrect bit count %d, must be 8 or 16\n", bits);
 101        return -1;
 102    }
 103
 104    if (nchannels != 1 && nchannels != 2) {
 105        term_printf ("incorrect channel count %d, must be 1 or 2\n",
 106                     nchannels);
 107        return -1;
 108    }
 109
 110    stereo = nchannels == 2;
 111    bits16 = bits == 16;
 112
 113    as.freq = freq;
 114    as.nchannels = 1 << stereo;
 115    as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
 116    as.endianness = 0;
 117
 118    ops.notify = wav_notify;
 119    ops.capture = wav_capture;
 120    ops.destroy = wav_destroy;
 121
 122    wav = qemu_mallocz (sizeof (*wav));
 123
 124    shift = bits16 + stereo;
 125    hdr[34] = bits16 ? 0x10 : 0x08;
 126
 127    le_store (hdr + 22, as.nchannels, 2);
 128    le_store (hdr + 24, freq, 4);
 129    le_store (hdr + 28, freq << shift, 4);
 130    le_store (hdr + 32, 1 << shift, 2);
 131
 132    wav->f = qemu_fopen (path, "wb");
 133    if (!wav->f) {
 134        term_printf ("Failed to open wave file `%s'\nReason: %s\n",
 135                     path, strerror (errno));
 136        qemu_free (wav);
 137        return -1;
 138    }
 139
 140    wav->path = qemu_strdup (path);
 141    wav->bits = bits;
 142    wav->nchannels = nchannels;
 143    wav->freq = freq;
 144
 145    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
 146
 147    cap = AUD_add_capture (NULL, &as, &ops, wav);
 148    if (!cap) {
 149        term_printf ("Failed to add audio capture\n");
 150        qemu_free (wav->path);
 151        qemu_fclose (wav->f);
 152        qemu_free (wav);
 153        return -1;
 154    }
 155
 156    wav->cap = cap;
 157    s->opaque = wav;
 158    s->ops = wav_capture_ops;
 159    return 0;
 160}
 161