qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

wavcapture.c (4901B)


      1 #include "qemu/osdep.h"
      2 #include "qemu/qemu-print.h"
      3 #include "qapi/error.h"
      4 #include "qemu/error-report.h"
      5 #include "audio.h"
      6 
      7 typedef 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. */
     18 static 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 
     27 static void wav_notify (void *opaque, audcnotification_e cmd)
     28 {
     29     (void) opaque;
     30     (void) cmd;
     31 }
     32 
     33 static 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 
     41     if (wav->f) {
     42         le_store (rlen, rifflen, 4);
     43         le_store (dlen, datalen, 4);
     44 
     45         if (fseek (wav->f, 4, SEEK_SET)) {
     46             error_report("wav_destroy: rlen fseek failed: %s",
     47                          strerror(errno));
     48             goto doclose;
     49         }
     50         if (fwrite (rlen, 4, 1, wav->f) != 1) {
     51             error_report("wav_destroy: rlen fwrite failed: %s",
     52                          strerror(errno));
     53             goto doclose;
     54         }
     55         if (fseek (wav->f, 32, SEEK_CUR)) {
     56             error_report("wav_destroy: dlen fseek failed: %s",
     57                          strerror(errno));
     58             goto doclose;
     59         }
     60         if (fwrite (dlen, 1, 4, wav->f) != 4) {
     61             error_report("wav_destroy: dlen fwrite failed: %s",
     62                          strerror(errno));
     63             goto doclose;
     64         }
     65     doclose:
     66         if (fclose (wav->f)) {
     67             error_report("wav_destroy: fclose failed: %s", strerror(errno));
     68         }
     69     }
     70 
     71     g_free (wav->path);
     72 }
     73 
     74 static void wav_capture(void *opaque, const void *buf, int size)
     75 {
     76     WAVState *wav = opaque;
     77 
     78     if (fwrite (buf, size, 1, wav->f) != 1) {
     79         error_report("wav_capture: fwrite error: %s", strerror(errno));
     80     }
     81     wav->bytes += size;
     82 }
     83 
     84 static void wav_capture_destroy (void *opaque)
     85 {
     86     WAVState *wav = opaque;
     87 
     88     AUD_del_capture (wav->cap, wav);
     89     g_free (wav);
     90 }
     91 
     92 static void wav_capture_info (void *opaque)
     93 {
     94     WAVState *wav = opaque;
     95     char *path = wav->path;
     96 
     97     qemu_printf("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 
    102 static struct capture_ops wav_capture_ops = {
    103     .destroy = wav_capture_destroy,
    104     .info = wav_capture_info
    105 };
    106 
    107 int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
    108                       int freq, int bits, int nchannels)
    109 {
    110     WAVState *wav;
    111     uint8_t hdr[] = {
    112         0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
    113         0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
    114         0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
    115         0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
    116     };
    117     struct audsettings as;
    118     struct audio_capture_ops ops;
    119     int stereo, bits16, shift;
    120     CaptureVoiceOut *cap;
    121 
    122     if (bits != 8 && bits != 16) {
    123         error_report("incorrect bit count %d, must be 8 or 16", bits);
    124         return -1;
    125     }
    126 
    127     if (nchannels != 1 && nchannels != 2) {
    128         error_report("incorrect channel count %d, must be 1 or 2",
    129                      nchannels);
    130         return -1;
    131     }
    132 
    133     stereo = nchannels == 2;
    134     bits16 = bits == 16;
    135 
    136     as.freq = freq;
    137     as.nchannels = 1 << stereo;
    138     as.fmt = bits16 ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8;
    139     as.endianness = 0;
    140 
    141     ops.notify = wav_notify;
    142     ops.capture = wav_capture;
    143     ops.destroy = wav_destroy;
    144 
    145     wav = g_malloc0 (sizeof (*wav));
    146 
    147     shift = bits16 + stereo;
    148     hdr[34] = bits16 ? 0x10 : 0x08;
    149 
    150     le_store (hdr + 22, as.nchannels, 2);
    151     le_store (hdr + 24, freq, 4);
    152     le_store (hdr + 28, freq << shift, 4);
    153     le_store (hdr + 32, 1 << shift, 2);
    154 
    155     wav->f = fopen (path, "wb");
    156     if (!wav->f) {
    157         error_report("Failed to open wave file `%s': %s",
    158                      path, strerror(errno));
    159         g_free (wav);
    160         return -1;
    161     }
    162 
    163     wav->path = g_strdup (path);
    164     wav->bits = bits;
    165     wav->nchannels = nchannels;
    166     wav->freq = freq;
    167 
    168     if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
    169         error_report("Failed to write header: %s", strerror(errno));
    170         goto error_free;
    171     }
    172 
    173     cap = AUD_add_capture(state, &as, &ops, wav);
    174     if (!cap) {
    175         error_report("Failed to add audio capture");
    176         goto error_free;
    177     }
    178 
    179     wav->cap = cap;
    180     s->opaque = wav;
    181     s->ops = wav_capture_ops;
    182     return 0;
    183 
    184 error_free:
    185     g_free (wav->path);
    186     if (fclose (wav->f)) {
    187         error_report("Failed to close wave file: %s", strerror(errno));
    188     }
    189     g_free (wav);
    190     return -1;
    191 }