Statistics
| Branch: | Revision:

root / audio / wavaudio.c @ 0f53994f

History | View | Annotate | Download (6.9 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 fb065187 bellard
    QEMUFile *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 85571bc7 bellard
    int64_t now = qemu_get_clock (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 1d14ffa9 bellard
        qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
80 85571bc7 bellard
81 85571bc7 bellard
        rpos = (rpos + convert_samples) % hw->samples;
82 85571bc7 bellard
        samples -= convert_samples;
83 85571bc7 bellard
        wav->total_samples += convert_samples;
84 85571bc7 bellard
    }
85 85571bc7 bellard
86 85571bc7 bellard
    hw->rpos = rpos;
87 1d14ffa9 bellard
    return decr;
88 85571bc7 bellard
}
89 85571bc7 bellard
90 1d14ffa9 bellard
static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
91 85571bc7 bellard
{
92 1d14ffa9 bellard
    return audio_pcm_sw_write (sw, buf, len);
93 85571bc7 bellard
}
94 85571bc7 bellard
95 85571bc7 bellard
/* VICE code: Store number as little endian. */
96 85571bc7 bellard
static void le_store (uint8_t *buf, uint32_t val, int len)
97 85571bc7 bellard
{
98 85571bc7 bellard
    int i;
99 85571bc7 bellard
    for (i = 0; i < len; i++) {
100 85571bc7 bellard
        buf[i] = (uint8_t) (val & 0xff);
101 85571bc7 bellard
        val >>= 8;
102 85571bc7 bellard
    }
103 85571bc7 bellard
}
104 85571bc7 bellard
105 1ea879e5 malc
static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
106 85571bc7 bellard
{
107 1d14ffa9 bellard
    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
108 c0fe3827 bellard
    int bits16 = 0, stereo = 0;
109 85571bc7 bellard
    uint8_t hdr[] = {
110 85571bc7 bellard
        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
111 85571bc7 bellard
        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
112 85571bc7 bellard
        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
113 85571bc7 bellard
        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
114 85571bc7 bellard
    };
115 1ea879e5 malc
    struct audsettings wav_as = conf.settings;
116 85571bc7 bellard
117 c0fe3827 bellard
    (void) as;
118 1d14ffa9 bellard
119 c0fe3827 bellard
    stereo = wav_as.nchannels == 2;
120 c0fe3827 bellard
    switch (wav_as.fmt) {
121 85571bc7 bellard
    case AUD_FMT_S8:
122 85571bc7 bellard
    case AUD_FMT_U8:
123 1d14ffa9 bellard
        bits16 = 0;
124 85571bc7 bellard
        break;
125 85571bc7 bellard
126 85571bc7 bellard
    case AUD_FMT_S16:
127 85571bc7 bellard
    case AUD_FMT_U16:
128 85571bc7 bellard
        bits16 = 1;
129 85571bc7 bellard
        break;
130 f941aa25 ths
131 f941aa25 ths
    case AUD_FMT_S32:
132 f941aa25 ths
    case AUD_FMT_U32:
133 f941aa25 ths
        dolog ("WAVE files can not handle 32bit formats\n");
134 f941aa25 ths
        return -1;
135 85571bc7 bellard
    }
136 85571bc7 bellard
137 85571bc7 bellard
    hdr[34] = bits16 ? 0x10 : 0x08;
138 c0fe3827 bellard
139 d929eba5 bellard
    wav_as.endianness = 0;
140 d929eba5 bellard
    audio_pcm_init_info (&hw->info, &wav_as);
141 c0fe3827 bellard
142 c0fe3827 bellard
    hw->samples = 1024;
143 c0fe3827 bellard
    wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
144 1d14ffa9 bellard
    if (!wav->pcm_buf) {
145 c0fe3827 bellard
        dolog ("Could not allocate buffer (%d bytes)\n",
146 c0fe3827 bellard
               hw->samples << hw->info.shift);
147 85571bc7 bellard
        return -1;
148 1d14ffa9 bellard
    }
149 85571bc7 bellard
150 1d14ffa9 bellard
    le_store (hdr + 22, hw->info.nchannels, 2);
151 1d14ffa9 bellard
    le_store (hdr + 24, hw->info.freq, 4);
152 c0fe3827 bellard
    le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
153 c0fe3827 bellard
    le_store (hdr + 32, 1 << (bits16 + stereo), 2);
154 85571bc7 bellard
155 e70332b3 bellard
    wav->f = qemu_fopen (conf.wav_path, "wb");
156 85571bc7 bellard
    if (!wav->f) {
157 1d14ffa9 bellard
        dolog ("Failed to open wave file `%s'\nReason: %s\n",
158 85571bc7 bellard
               conf.wav_path, strerror (errno));
159 7372f88d bellard
        qemu_free (wav->pcm_buf);
160 7372f88d bellard
        wav->pcm_buf = NULL;
161 85571bc7 bellard
        return -1;
162 85571bc7 bellard
    }
163 85571bc7 bellard
164 85571bc7 bellard
    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
165 85571bc7 bellard
    return 0;
166 85571bc7 bellard
}
167 85571bc7 bellard
168 1d14ffa9 bellard
static void wav_fini_out (HWVoiceOut *hw)
169 85571bc7 bellard
{
170 1d14ffa9 bellard
    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
171 85571bc7 bellard
    uint8_t rlen[4];
172 85571bc7 bellard
    uint8_t dlen[4];
173 50903530 bellard
    uint32_t datalen = wav->total_samples << hw->info.shift;
174 50903530 bellard
    uint32_t rifflen = datalen + 36;
175 85571bc7 bellard
176 c0fe3827 bellard
    if (!wav->f) {
177 85571bc7 bellard
        return;
178 1d14ffa9 bellard
    }
179 85571bc7 bellard
180 85571bc7 bellard
    le_store (rlen, rifflen, 4);
181 85571bc7 bellard
    le_store (dlen, datalen, 4);
182 85571bc7 bellard
183 85571bc7 bellard
    qemu_fseek (wav->f, 4, SEEK_SET);
184 85571bc7 bellard
    qemu_put_buffer (wav->f, rlen, 4);
185 85571bc7 bellard
186 85571bc7 bellard
    qemu_fseek (wav->f, 32, SEEK_CUR);
187 85571bc7 bellard
    qemu_put_buffer (wav->f, dlen, 4);
188 85571bc7 bellard
189 e70332b3 bellard
    qemu_fclose (wav->f);
190 85571bc7 bellard
    wav->f = NULL;
191 7372f88d bellard
192 7372f88d bellard
    qemu_free (wav->pcm_buf);
193 7372f88d bellard
    wav->pcm_buf = NULL;
194 85571bc7 bellard
}
195 85571bc7 bellard
196 1d14ffa9 bellard
static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
197 85571bc7 bellard
{
198 85571bc7 bellard
    (void) hw;
199 85571bc7 bellard
    (void) cmd;
200 85571bc7 bellard
    return 0;
201 85571bc7 bellard
}
202 85571bc7 bellard
203 85571bc7 bellard
static void *wav_audio_init (void)
204 85571bc7 bellard
{
205 85571bc7 bellard
    return &conf;
206 85571bc7 bellard
}
207 85571bc7 bellard
208 85571bc7 bellard
static void wav_audio_fini (void *opaque)
209 85571bc7 bellard
{
210 1d14ffa9 bellard
    (void) opaque;
211 85571bc7 bellard
    ldebug ("wav_fini");
212 85571bc7 bellard
}
213 85571bc7 bellard
214 8869defe blueswir1
static struct audio_option wav_options[] = {
215 98f9f48c malc
    {
216 98f9f48c malc
        .name  = "FREQUENCY",
217 98f9f48c malc
        .tag   = AUD_OPT_INT,
218 98f9f48c malc
        .valp  = &conf.settings.freq,
219 98f9f48c malc
        .descr = "Frequency"
220 98f9f48c malc
    },
221 98f9f48c malc
    {
222 98f9f48c malc
        .name  = "FORMAT",
223 98f9f48c malc
        .tag   = AUD_OPT_FMT,
224 98f9f48c malc
        .valp  = &conf.settings.fmt,
225 98f9f48c malc
        .descr = "Format"
226 98f9f48c malc
    },
227 98f9f48c malc
    {
228 98f9f48c malc
        .name  = "DAC_FIXED_CHANNELS",
229 98f9f48c malc
        .tag   = AUD_OPT_INT,
230 98f9f48c malc
        .valp  = &conf.settings.nchannels,
231 98f9f48c malc
        .descr = "Number of channels (1 - mono, 2 - stereo)"
232 98f9f48c malc
    },
233 98f9f48c malc
    {
234 98f9f48c malc
        .name  = "PATH",
235 98f9f48c malc
        .tag   = AUD_OPT_STR,
236 98f9f48c malc
        .valp  = &conf.wav_path,
237 98f9f48c malc
        .descr = "Path to wave file"
238 98f9f48c malc
    },
239 2700efa3 Juan Quintela
    { /* End of list */ }
240 1d14ffa9 bellard
};
241 1d14ffa9 bellard
242 35f4b58c blueswir1
static struct audio_pcm_ops wav_pcm_ops = {
243 1dd3e4d1 Juan Quintela
    .init_out = wav_init_out,
244 1dd3e4d1 Juan Quintela
    .fini_out = wav_fini_out,
245 1dd3e4d1 Juan Quintela
    .run_out  = wav_run_out,
246 1dd3e4d1 Juan Quintela
    .write    = wav_write_out,
247 1dd3e4d1 Juan Quintela
    .ctl_out  = wav_ctl_out,
248 85571bc7 bellard
};
249 85571bc7 bellard
250 1d14ffa9 bellard
struct audio_driver wav_audio_driver = {
251 bee37f32 Juan Quintela
    .name           = "wav",
252 bee37f32 Juan Quintela
    .descr          = "WAV renderer http://wikipedia.org/wiki/WAV",
253 bee37f32 Juan Quintela
    .options        = wav_options,
254 bee37f32 Juan Quintela
    .init           = wav_audio_init,
255 bee37f32 Juan Quintela
    .fini           = wav_audio_fini,
256 98f9f48c malc
    .pcm_ops        = &wav_pcm_ops,
257 bee37f32 Juan Quintela
    .can_be_default = 0,
258 bee37f32 Juan Quintela
    .max_voices_out = 1,
259 bee37f32 Juan Quintela
    .max_voices_in  = 0,
260 bee37f32 Juan Quintela
    .voice_size_out = sizeof (WAVVoiceOut),
261 bee37f32 Juan Quintela
    .voice_size_in  = 0
262 85571bc7 bellard
};