Statistics
| Branch: | Revision:

root / audio / wavaudio.c @ 87ecb68b

History | View | Annotate | Download (6.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 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 c0fe3827 bellard
    audsettings_t settings;
41 85571bc7 bellard
    const char *wav_path;
42 85571bc7 bellard
} conf = {
43 c0fe3827 bellard
    {
44 c0fe3827 bellard
        44100,
45 c0fe3827 bellard
        2,
46 f941aa25 ths
        AUD_FMT_S16,
47 f941aa25 ths
        AUDIO_HOST_ENDIANNESS
48 c0fe3827 bellard
    },
49 c0fe3827 bellard
    "qemu.wav"
50 85571bc7 bellard
};
51 85571bc7 bellard
52 1d14ffa9 bellard
static int wav_run_out (HWVoiceOut *hw)
53 85571bc7 bellard
{
54 1d14ffa9 bellard
    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
55 85571bc7 bellard
    int rpos, live, decr, samples;
56 85571bc7 bellard
    uint8_t *dst;
57 85571bc7 bellard
    st_sample_t *src;
58 85571bc7 bellard
    int64_t now = qemu_get_clock (vm_clock);
59 85571bc7 bellard
    int64_t ticks = now - wav->old_ticks;
60 1d14ffa9 bellard
    int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
61 85571bc7 bellard
62 1d14ffa9 bellard
    if (bytes > INT_MAX) {
63 1d14ffa9 bellard
        samples = INT_MAX >> hw->info.shift;
64 1d14ffa9 bellard
    }
65 1d14ffa9 bellard
    else {
66 1d14ffa9 bellard
        samples = bytes >> hw->info.shift;
67 1d14ffa9 bellard
    }
68 85571bc7 bellard
69 1d14ffa9 bellard
    live = audio_pcm_hw_get_live_out (hw);
70 1d14ffa9 bellard
    if (!live) {
71 1d14ffa9 bellard
        return 0;
72 1d14ffa9 bellard
    }
73 85571bc7 bellard
74 7372f88d bellard
    wav->old_ticks = now;
75 85571bc7 bellard
    decr = audio_MIN (live, samples);
76 85571bc7 bellard
    samples = decr;
77 85571bc7 bellard
    rpos = hw->rpos;
78 85571bc7 bellard
    while (samples) {
79 85571bc7 bellard
        int left_till_end_samples = hw->samples - rpos;
80 85571bc7 bellard
        int convert_samples = audio_MIN (samples, left_till_end_samples);
81 85571bc7 bellard
82 1d14ffa9 bellard
        src = hw->mix_buf + rpos;
83 1d14ffa9 bellard
        dst = advance (wav->pcm_buf, rpos << hw->info.shift);
84 85571bc7 bellard
85 85571bc7 bellard
        hw->clip (dst, src, convert_samples);
86 1d14ffa9 bellard
        qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
87 85571bc7 bellard
88 85571bc7 bellard
        rpos = (rpos + convert_samples) % hw->samples;
89 85571bc7 bellard
        samples -= convert_samples;
90 85571bc7 bellard
        wav->total_samples += convert_samples;
91 85571bc7 bellard
    }
92 85571bc7 bellard
93 85571bc7 bellard
    hw->rpos = rpos;
94 1d14ffa9 bellard
    return decr;
95 85571bc7 bellard
}
96 85571bc7 bellard
97 1d14ffa9 bellard
static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
98 85571bc7 bellard
{
99 1d14ffa9 bellard
    return audio_pcm_sw_write (sw, buf, len);
100 85571bc7 bellard
}
101 85571bc7 bellard
102 85571bc7 bellard
/* VICE code: Store number as little endian. */
103 85571bc7 bellard
static void le_store (uint8_t *buf, uint32_t val, int len)
104 85571bc7 bellard
{
105 85571bc7 bellard
    int i;
106 85571bc7 bellard
    for (i = 0; i < len; i++) {
107 85571bc7 bellard
        buf[i] = (uint8_t) (val & 0xff);
108 85571bc7 bellard
        val >>= 8;
109 85571bc7 bellard
    }
110 85571bc7 bellard
}
111 85571bc7 bellard
112 c0fe3827 bellard
static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
113 85571bc7 bellard
{
114 1d14ffa9 bellard
    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
115 c0fe3827 bellard
    int bits16 = 0, stereo = 0;
116 85571bc7 bellard
    uint8_t hdr[] = {
117 85571bc7 bellard
        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
118 85571bc7 bellard
        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
119 85571bc7 bellard
        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
120 85571bc7 bellard
        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
121 85571bc7 bellard
    };
122 c0fe3827 bellard
    audsettings_t wav_as = conf.settings;
123 85571bc7 bellard
124 c0fe3827 bellard
    (void) as;
125 1d14ffa9 bellard
126 c0fe3827 bellard
    stereo = wav_as.nchannels == 2;
127 c0fe3827 bellard
    switch (wav_as.fmt) {
128 85571bc7 bellard
    case AUD_FMT_S8:
129 85571bc7 bellard
    case AUD_FMT_U8:
130 1d14ffa9 bellard
        bits16 = 0;
131 85571bc7 bellard
        break;
132 85571bc7 bellard
133 85571bc7 bellard
    case AUD_FMT_S16:
134 85571bc7 bellard
    case AUD_FMT_U16:
135 85571bc7 bellard
        bits16 = 1;
136 85571bc7 bellard
        break;
137 f941aa25 ths
138 f941aa25 ths
    case AUD_FMT_S32:
139 f941aa25 ths
    case AUD_FMT_U32:
140 f941aa25 ths
        dolog ("WAVE files can not handle 32bit formats\n");
141 f941aa25 ths
        return -1;
142 85571bc7 bellard
    }
143 85571bc7 bellard
144 85571bc7 bellard
    hdr[34] = bits16 ? 0x10 : 0x08;
145 c0fe3827 bellard
146 d929eba5 bellard
    wav_as.endianness = 0;
147 d929eba5 bellard
    audio_pcm_init_info (&hw->info, &wav_as);
148 c0fe3827 bellard
149 c0fe3827 bellard
    hw->samples = 1024;
150 c0fe3827 bellard
    wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
151 1d14ffa9 bellard
    if (!wav->pcm_buf) {
152 c0fe3827 bellard
        dolog ("Could not allocate buffer (%d bytes)\n",
153 c0fe3827 bellard
               hw->samples << hw->info.shift);
154 85571bc7 bellard
        return -1;
155 1d14ffa9 bellard
    }
156 85571bc7 bellard
157 1d14ffa9 bellard
    le_store (hdr + 22, hw->info.nchannels, 2);
158 1d14ffa9 bellard
    le_store (hdr + 24, hw->info.freq, 4);
159 c0fe3827 bellard
    le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
160 c0fe3827 bellard
    le_store (hdr + 32, 1 << (bits16 + stereo), 2);
161 85571bc7 bellard
162 e70332b3 bellard
    wav->f = qemu_fopen (conf.wav_path, "wb");
163 85571bc7 bellard
    if (!wav->f) {
164 1d14ffa9 bellard
        dolog ("Failed to open wave file `%s'\nReason: %s\n",
165 85571bc7 bellard
               conf.wav_path, strerror (errno));
166 7372f88d bellard
        qemu_free (wav->pcm_buf);
167 7372f88d bellard
        wav->pcm_buf = NULL;
168 85571bc7 bellard
        return -1;
169 85571bc7 bellard
    }
170 85571bc7 bellard
171 85571bc7 bellard
    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
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 85571bc7 bellard
    qemu_fseek (wav->f, 4, SEEK_SET);
191 85571bc7 bellard
    qemu_put_buffer (wav->f, rlen, 4);
192 85571bc7 bellard
193 85571bc7 bellard
    qemu_fseek (wav->f, 32, SEEK_CUR);
194 85571bc7 bellard
    qemu_put_buffer (wav->f, dlen, 4);
195 85571bc7 bellard
196 e70332b3 bellard
    qemu_fclose (wav->f);
197 85571bc7 bellard
    wav->f = NULL;
198 7372f88d bellard
199 7372f88d bellard
    qemu_free (wav->pcm_buf);
200 7372f88d bellard
    wav->pcm_buf = NULL;
201 85571bc7 bellard
}
202 85571bc7 bellard
203 1d14ffa9 bellard
static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
204 85571bc7 bellard
{
205 85571bc7 bellard
    (void) hw;
206 85571bc7 bellard
    (void) cmd;
207 85571bc7 bellard
    return 0;
208 85571bc7 bellard
}
209 85571bc7 bellard
210 85571bc7 bellard
static void *wav_audio_init (void)
211 85571bc7 bellard
{
212 85571bc7 bellard
    return &conf;
213 85571bc7 bellard
}
214 85571bc7 bellard
215 85571bc7 bellard
static void wav_audio_fini (void *opaque)
216 85571bc7 bellard
{
217 1d14ffa9 bellard
    (void) opaque;
218 85571bc7 bellard
    ldebug ("wav_fini");
219 85571bc7 bellard
}
220 85571bc7 bellard
221 1d14ffa9 bellard
struct audio_option wav_options[] = {
222 c0fe3827 bellard
    {"FREQUENCY", AUD_OPT_INT, &conf.settings.freq,
223 c0fe3827 bellard
     "Frequency", NULL, 0},
224 c0fe3827 bellard
225 c0fe3827 bellard
    {"FORMAT", AUD_OPT_FMT, &conf.settings.fmt,
226 c0fe3827 bellard
     "Format", NULL, 0},
227 c0fe3827 bellard
228 c0fe3827 bellard
    {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels,
229 c0fe3827 bellard
     "Number of channels (1 - mono, 2 - stereo)", NULL, 0},
230 c0fe3827 bellard
231 1d14ffa9 bellard
    {"PATH", AUD_OPT_STR, &conf.wav_path,
232 1d14ffa9 bellard
     "Path to wave file", NULL, 0},
233 1d14ffa9 bellard
    {NULL, 0, NULL, NULL, NULL, 0}
234 1d14ffa9 bellard
};
235 1d14ffa9 bellard
236 1d14ffa9 bellard
struct audio_pcm_ops wav_pcm_ops = {
237 1d14ffa9 bellard
    wav_init_out,
238 1d14ffa9 bellard
    wav_fini_out,
239 1d14ffa9 bellard
    wav_run_out,
240 1d14ffa9 bellard
    wav_write_out,
241 1d14ffa9 bellard
    wav_ctl_out,
242 1d14ffa9 bellard
243 1d14ffa9 bellard
    NULL,
244 1d14ffa9 bellard
    NULL,
245 1d14ffa9 bellard
    NULL,
246 1d14ffa9 bellard
    NULL,
247 1d14ffa9 bellard
    NULL
248 85571bc7 bellard
};
249 85571bc7 bellard
250 1d14ffa9 bellard
struct audio_driver wav_audio_driver = {
251 1d14ffa9 bellard
    INIT_FIELD (name           = ) "wav",
252 1d14ffa9 bellard
    INIT_FIELD (descr          = )
253 1d14ffa9 bellard
    "WAV renderer http://wikipedia.org/wiki/WAV",
254 1d14ffa9 bellard
    INIT_FIELD (options        = ) wav_options,
255 1d14ffa9 bellard
    INIT_FIELD (init           = ) wav_audio_init,
256 1d14ffa9 bellard
    INIT_FIELD (fini           = ) wav_audio_fini,
257 1d14ffa9 bellard
    INIT_FIELD (pcm_ops        = ) &wav_pcm_ops,
258 1d14ffa9 bellard
    INIT_FIELD (can_be_default = ) 0,
259 1d14ffa9 bellard
    INIT_FIELD (max_voices_out = ) 1,
260 1d14ffa9 bellard
    INIT_FIELD (max_voices_in  = ) 0,
261 1d14ffa9 bellard
    INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut),
262 1d14ffa9 bellard
    INIT_FIELD (voice_size_in  = ) 0
263 85571bc7 bellard
};