Statistics
| Branch: | Revision:

root / audio / wavaudio.c @ ea785922

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