Statistics
| Branch: | Revision:

root / audio / wavaudio.c @ 814589c4

History | View | Annotate | Download (7.8 kB)

1 85571bc7 bellard
/*
2 1d14ffa9 bellard
 * QEMU WAV audio driver
3 1d14ffa9 bellard
 *
4 1d14ffa9 bellard
 * Copyright (c) 2004-2005 Vassili Karpov (malc)
5 1d14ffa9 bellard
 *
6 85571bc7 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 85571bc7 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 85571bc7 bellard
 * in the Software without restriction, including without limitation the rights
9 85571bc7 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 85571bc7 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 85571bc7 bellard
 * furnished to do so, subject to the following conditions:
12 85571bc7 bellard
 *
13 85571bc7 bellard
 * The above copyright notice and this permission notice shall be included in
14 85571bc7 bellard
 * all copies or substantial portions of the Software.
15 85571bc7 bellard
 *
16 85571bc7 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 85571bc7 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 85571bc7 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 85571bc7 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 85571bc7 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 85571bc7 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 85571bc7 bellard
 * THE SOFTWARE.
23 85571bc7 bellard
 */
24 87ecb68b pbrook
#include "hw/hw.h"
25 87ecb68b pbrook
#include "qemu-timer.h"
26 87ecb68b pbrook
#include "audio.h"
27 85571bc7 bellard
28 1d14ffa9 bellard
#define AUDIO_CAP "wav"
29 1d14ffa9 bellard
#include "audio_int.h"
30 fb065187 bellard
31 1d14ffa9 bellard
typedef struct WAVVoiceOut {
32 1d14ffa9 bellard
    HWVoiceOut hw;
33 27acf660 Juan Quintela
    FILE *f;
34 fb065187 bellard
    int64_t old_ticks;
35 fb065187 bellard
    void *pcm_buf;
36 fb065187 bellard
    int total_samples;
37 1d14ffa9 bellard
} WAVVoiceOut;
38 85571bc7 bellard
39 85571bc7 bellard
static struct {
40 1ea879e5 malc
    struct audsettings settings;
41 85571bc7 bellard
    const char *wav_path;
42 85571bc7 bellard
} conf = {
43 1a40d5e2 Juan Quintela
    .settings.freq      = 44100,
44 1a40d5e2 Juan Quintela
    .settings.nchannels = 2,
45 1a40d5e2 Juan Quintela
    .settings.fmt       = AUD_FMT_S16,
46 1a40d5e2 Juan Quintela
    .wav_path           = "qemu.wav"
47 85571bc7 bellard
};
48 85571bc7 bellard
49 bdff253c malc
static int wav_run_out (HWVoiceOut *hw, int live)
50 85571bc7 bellard
{
51 1d14ffa9 bellard
    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
52 bdff253c malc
    int rpos, decr, samples;
53 85571bc7 bellard
    uint8_t *dst;
54 1ea879e5 malc
    struct st_sample *src;
55 74475455 Paolo Bonzini
    int64_t now = qemu_get_clock_ns (vm_clock);
56 85571bc7 bellard
    int64_t ticks = now - wav->old_ticks;
57 4f4cc0ef malc
    int64_t bytes =
58 4f4cc0ef malc
        muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
59 85571bc7 bellard
60 1d14ffa9 bellard
    if (bytes > INT_MAX) {
61 1d14ffa9 bellard
        samples = INT_MAX >> hw->info.shift;
62 1d14ffa9 bellard
    }
63 1d14ffa9 bellard
    else {
64 1d14ffa9 bellard
        samples = bytes >> hw->info.shift;
65 1d14ffa9 bellard
    }
66 85571bc7 bellard
67 7372f88d bellard
    wav->old_ticks = now;
68 85571bc7 bellard
    decr = audio_MIN (live, samples);
69 85571bc7 bellard
    samples = decr;
70 85571bc7 bellard
    rpos = hw->rpos;
71 85571bc7 bellard
    while (samples) {
72 85571bc7 bellard
        int left_till_end_samples = hw->samples - rpos;
73 85571bc7 bellard
        int convert_samples = audio_MIN (samples, left_till_end_samples);
74 85571bc7 bellard
75 1d14ffa9 bellard
        src = hw->mix_buf + rpos;
76 1d14ffa9 bellard
        dst = advance (wav->pcm_buf, rpos << hw->info.shift);
77 85571bc7 bellard
78 85571bc7 bellard
        hw->clip (dst, src, convert_samples);
79 27acf660 Juan Quintela
        if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) {
80 27acf660 Juan Quintela
            dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n",
81 27acf660 Juan Quintela
                   convert_samples << hw->info.shift, strerror (errno));
82 27acf660 Juan Quintela
        }
83 85571bc7 bellard
84 85571bc7 bellard
        rpos = (rpos + convert_samples) % hw->samples;
85 85571bc7 bellard
        samples -= convert_samples;
86 85571bc7 bellard
        wav->total_samples += convert_samples;
87 85571bc7 bellard
    }
88 85571bc7 bellard
89 85571bc7 bellard
    hw->rpos = rpos;
90 1d14ffa9 bellard
    return decr;
91 85571bc7 bellard
}
92 85571bc7 bellard
93 1d14ffa9 bellard
static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
94 85571bc7 bellard
{
95 1d14ffa9 bellard
    return audio_pcm_sw_write (sw, buf, len);
96 85571bc7 bellard
}
97 85571bc7 bellard
98 85571bc7 bellard
/* VICE code: Store number as little endian. */
99 85571bc7 bellard
static void le_store (uint8_t *buf, uint32_t val, int len)
100 85571bc7 bellard
{
101 85571bc7 bellard
    int i;
102 85571bc7 bellard
    for (i = 0; i < len; i++) {
103 85571bc7 bellard
        buf[i] = (uint8_t) (val & 0xff);
104 85571bc7 bellard
        val >>= 8;
105 85571bc7 bellard
    }
106 85571bc7 bellard
}
107 85571bc7 bellard
108 1ea879e5 malc
static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
109 85571bc7 bellard
{
110 1d14ffa9 bellard
    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
111 c0fe3827 bellard
    int bits16 = 0, stereo = 0;
112 85571bc7 bellard
    uint8_t hdr[] = {
113 85571bc7 bellard
        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
114 85571bc7 bellard
        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
115 85571bc7 bellard
        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
116 85571bc7 bellard
        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
117 85571bc7 bellard
    };
118 1ea879e5 malc
    struct audsettings wav_as = conf.settings;
119 85571bc7 bellard
120 c0fe3827 bellard
    (void) as;
121 1d14ffa9 bellard
122 c0fe3827 bellard
    stereo = wav_as.nchannels == 2;
123 c0fe3827 bellard
    switch (wav_as.fmt) {
124 85571bc7 bellard
    case AUD_FMT_S8:
125 85571bc7 bellard
    case AUD_FMT_U8:
126 1d14ffa9 bellard
        bits16 = 0;
127 85571bc7 bellard
        break;
128 85571bc7 bellard
129 85571bc7 bellard
    case AUD_FMT_S16:
130 85571bc7 bellard
    case AUD_FMT_U16:
131 85571bc7 bellard
        bits16 = 1;
132 85571bc7 bellard
        break;
133 f941aa25 ths
134 f941aa25 ths
    case AUD_FMT_S32:
135 f941aa25 ths
    case AUD_FMT_U32:
136 f941aa25 ths
        dolog ("WAVE files can not handle 32bit formats\n");
137 f941aa25 ths
        return -1;
138 85571bc7 bellard
    }
139 85571bc7 bellard
140 85571bc7 bellard
    hdr[34] = bits16 ? 0x10 : 0x08;
141 c0fe3827 bellard
142 d929eba5 bellard
    wav_as.endianness = 0;
143 d929eba5 bellard
    audio_pcm_init_info (&hw->info, &wav_as);
144 c0fe3827 bellard
145 c0fe3827 bellard
    hw->samples = 1024;
146 c0fe3827 bellard
    wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
147 1d14ffa9 bellard
    if (!wav->pcm_buf) {
148 c0fe3827 bellard
        dolog ("Could not allocate buffer (%d bytes)\n",
149 c0fe3827 bellard
               hw->samples << hw->info.shift);
150 85571bc7 bellard
        return -1;
151 1d14ffa9 bellard
    }
152 85571bc7 bellard
153 1d14ffa9 bellard
    le_store (hdr + 22, hw->info.nchannels, 2);
154 1d14ffa9 bellard
    le_store (hdr + 24, hw->info.freq, 4);
155 c0fe3827 bellard
    le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
156 c0fe3827 bellard
    le_store (hdr + 32, 1 << (bits16 + stereo), 2);
157 85571bc7 bellard
158 27acf660 Juan Quintela
    wav->f = fopen (conf.wav_path, "wb");
159 85571bc7 bellard
    if (!wav->f) {
160 1d14ffa9 bellard
        dolog ("Failed to open wave file `%s'\nReason: %s\n",
161 85571bc7 bellard
               conf.wav_path, strerror (errno));
162 7267c094 Anthony Liguori
        g_free (wav->pcm_buf);
163 7372f88d bellard
        wav->pcm_buf = NULL;
164 85571bc7 bellard
        return -1;
165 85571bc7 bellard
    }
166 85571bc7 bellard
167 27acf660 Juan Quintela
    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
168 27acf660 Juan Quintela
        dolog ("wav_init_out: failed to write header\nReason: %s\n",
169 27acf660 Juan Quintela
               strerror(errno));
170 27acf660 Juan Quintela
        return -1;
171 27acf660 Juan Quintela
    }
172 85571bc7 bellard
    return 0;
173 85571bc7 bellard
}
174 85571bc7 bellard
175 1d14ffa9 bellard
static void wav_fini_out (HWVoiceOut *hw)
176 85571bc7 bellard
{
177 1d14ffa9 bellard
    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
178 85571bc7 bellard
    uint8_t rlen[4];
179 85571bc7 bellard
    uint8_t dlen[4];
180 50903530 bellard
    uint32_t datalen = wav->total_samples << hw->info.shift;
181 50903530 bellard
    uint32_t rifflen = datalen + 36;
182 85571bc7 bellard
183 c0fe3827 bellard
    if (!wav->f) {
184 85571bc7 bellard
        return;
185 1d14ffa9 bellard
    }
186 85571bc7 bellard
187 85571bc7 bellard
    le_store (rlen, rifflen, 4);
188 85571bc7 bellard
    le_store (dlen, datalen, 4);
189 85571bc7 bellard
190 27acf660 Juan Quintela
    if (fseek (wav->f, 4, SEEK_SET)) {
191 27acf660 Juan Quintela
        dolog ("wav_fini_out: fseek to rlen failed\nReason: %s\n",
192 27acf660 Juan Quintela
               strerror(errno));
193 27acf660 Juan Quintela
        goto doclose;
194 27acf660 Juan Quintela
    }
195 27acf660 Juan Quintela
    if (fwrite (rlen, 4, 1, wav->f) != 1) {
196 27acf660 Juan Quintela
        dolog ("wav_fini_out: failed to write rlen\nReason: %s\n",
197 27acf660 Juan Quintela
               strerror (errno));
198 27acf660 Juan Quintela
        goto doclose;
199 27acf660 Juan Quintela
    }
200 27acf660 Juan Quintela
    if (fseek (wav->f, 32, SEEK_CUR)) {
201 27acf660 Juan Quintela
        dolog ("wav_fini_out: fseek to dlen failed\nReason: %s\n",
202 27acf660 Juan Quintela
               strerror (errno));
203 27acf660 Juan Quintela
        goto doclose;
204 27acf660 Juan Quintela
    }
205 27acf660 Juan Quintela
    if (fwrite (dlen, 4, 1, wav->f) != 1) {
206 27acf660 Juan Quintela
        dolog ("wav_fini_out: failed to write dlen\nReaons: %s\n",
207 27acf660 Juan Quintela
               strerror (errno));
208 27acf660 Juan Quintela
        goto doclose;
209 27acf660 Juan Quintela
    }
210 85571bc7 bellard
211 27acf660 Juan Quintela
 doclose:
212 27acf660 Juan Quintela
    if (fclose (wav->f))  {
213 27acf660 Juan Quintela
        dolog ("wav_fini_out: fclose %p failed\nReason: %s\n",
214 27acf660 Juan Quintela
               wav->f, strerror (errno));
215 27acf660 Juan Quintela
    }
216 85571bc7 bellard
    wav->f = NULL;
217 7372f88d bellard
218 7267c094 Anthony Liguori
    g_free (wav->pcm_buf);
219 7372f88d bellard
    wav->pcm_buf = NULL;
220 85571bc7 bellard
}
221 85571bc7 bellard
222 1d14ffa9 bellard
static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
223 85571bc7 bellard
{
224 85571bc7 bellard
    (void) hw;
225 85571bc7 bellard
    (void) cmd;
226 85571bc7 bellard
    return 0;
227 85571bc7 bellard
}
228 85571bc7 bellard
229 85571bc7 bellard
static void *wav_audio_init (void)
230 85571bc7 bellard
{
231 85571bc7 bellard
    return &conf;
232 85571bc7 bellard
}
233 85571bc7 bellard
234 85571bc7 bellard
static void wav_audio_fini (void *opaque)
235 85571bc7 bellard
{
236 1d14ffa9 bellard
    (void) opaque;
237 85571bc7 bellard
    ldebug ("wav_fini");
238 85571bc7 bellard
}
239 85571bc7 bellard
240 8869defe blueswir1
static struct audio_option wav_options[] = {
241 98f9f48c malc
    {
242 98f9f48c malc
        .name  = "FREQUENCY",
243 98f9f48c malc
        .tag   = AUD_OPT_INT,
244 98f9f48c malc
        .valp  = &conf.settings.freq,
245 98f9f48c malc
        .descr = "Frequency"
246 98f9f48c malc
    },
247 98f9f48c malc
    {
248 98f9f48c malc
        .name  = "FORMAT",
249 98f9f48c malc
        .tag   = AUD_OPT_FMT,
250 98f9f48c malc
        .valp  = &conf.settings.fmt,
251 98f9f48c malc
        .descr = "Format"
252 98f9f48c malc
    },
253 98f9f48c malc
    {
254 98f9f48c malc
        .name  = "DAC_FIXED_CHANNELS",
255 98f9f48c malc
        .tag   = AUD_OPT_INT,
256 98f9f48c malc
        .valp  = &conf.settings.nchannels,
257 98f9f48c malc
        .descr = "Number of channels (1 - mono, 2 - stereo)"
258 98f9f48c malc
    },
259 98f9f48c malc
    {
260 98f9f48c malc
        .name  = "PATH",
261 98f9f48c malc
        .tag   = AUD_OPT_STR,
262 98f9f48c malc
        .valp  = &conf.wav_path,
263 98f9f48c malc
        .descr = "Path to wave file"
264 98f9f48c malc
    },
265 2700efa3 Juan Quintela
    { /* End of list */ }
266 1d14ffa9 bellard
};
267 1d14ffa9 bellard
268 35f4b58c blueswir1
static struct audio_pcm_ops wav_pcm_ops = {
269 1dd3e4d1 Juan Quintela
    .init_out = wav_init_out,
270 1dd3e4d1 Juan Quintela
    .fini_out = wav_fini_out,
271 1dd3e4d1 Juan Quintela
    .run_out  = wav_run_out,
272 1dd3e4d1 Juan Quintela
    .write    = wav_write_out,
273 1dd3e4d1 Juan Quintela
    .ctl_out  = wav_ctl_out,
274 85571bc7 bellard
};
275 85571bc7 bellard
276 1d14ffa9 bellard
struct audio_driver wav_audio_driver = {
277 bee37f32 Juan Quintela
    .name           = "wav",
278 bee37f32 Juan Quintela
    .descr          = "WAV renderer http://wikipedia.org/wiki/WAV",
279 bee37f32 Juan Quintela
    .options        = wav_options,
280 bee37f32 Juan Quintela
    .init           = wav_audio_init,
281 bee37f32 Juan Quintela
    .fini           = wav_audio_fini,
282 98f9f48c malc
    .pcm_ops        = &wav_pcm_ops,
283 bee37f32 Juan Quintela
    .can_be_default = 0,
284 bee37f32 Juan Quintela
    .max_voices_out = 1,
285 bee37f32 Juan Quintela
    .max_voices_in  = 0,
286 bee37f32 Juan Quintela
    .voice_size_out = sizeof (WAVVoiceOut),
287 bee37f32 Juan Quintela
    .voice_size_in  = 0
288 85571bc7 bellard
};