Statistics
| Branch: | Revision:

root / audio / wavcapture.c @ b04df2a4

History | View | Annotate | Download (5 kB)

1
#include "hw/hw.h"
2
#include "monitor.h"
3
#include "audio.h"
4

    
5
typedef 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. */
16
static 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

    
25
static void wav_notify (void *opaque, audcnotification_e cmd)
26
{
27
    (void) opaque;
28
    (void) cmd;
29
}
30

    
31
static 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

    
74
static 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

    
85
static void wav_capture_destroy (void *opaque)
86
{
87
    WAVState *wav = opaque;
88

    
89
    AUD_del_capture (wav->cap, wav);
90
}
91

    
92
static 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

    
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 (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

    
186
error_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
}