Statistics
| Branch: | Revision:

root / audio / wavaudio.c @ d3c61721

History | View | Annotate | Download (5.6 kB)

1 85571bc7 bellard
/*
2 85571bc7 bellard
 * QEMU WAV audio output driver
3 85571bc7 bellard
 * 
4 85571bc7 bellard
 * Copyright (c) 2004 Vassili Karpov (malc)
5 85571bc7 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 fb065187 bellard
#include "audio/audio_int.h"
27 fb065187 bellard
28 fb065187 bellard
typedef struct WAVVoice {
29 fb065187 bellard
    HWVoice hw;
30 fb065187 bellard
    QEMUFile *f;
31 fb065187 bellard
    int64_t old_ticks;
32 fb065187 bellard
    void *pcm_buf;
33 fb065187 bellard
    int total_samples;
34 fb065187 bellard
} WAVVoice;
35 fb065187 bellard
36 fb065187 bellard
#define dolog(...) AUD_log ("wav", __VA_ARGS__)
37 fb065187 bellard
#ifdef DEBUG
38 fb065187 bellard
#define ldebug(...) dolog (__VA_ARGS__)
39 fb065187 bellard
#else
40 fb065187 bellard
#define ldebug(...)
41 fb065187 bellard
#endif
42 85571bc7 bellard
43 85571bc7 bellard
static struct {
44 85571bc7 bellard
    const char *wav_path;
45 85571bc7 bellard
} conf = {
46 85571bc7 bellard
    .wav_path = "qemu.wav"
47 85571bc7 bellard
};
48 85571bc7 bellard
49 85571bc7 bellard
static void wav_hw_run (HWVoice *hw)
50 85571bc7 bellard
{
51 85571bc7 bellard
    WAVVoice *wav = (WAVVoice *) 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 85571bc7 bellard
    int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
58 85571bc7 bellard
59 85571bc7 bellard
    if (bytes > INT_MAX)
60 85571bc7 bellard
        samples = INT_MAX >> hw->shift;
61 85571bc7 bellard
    else
62 85571bc7 bellard
        samples = bytes >> hw->shift;
63 85571bc7 bellard
64 85571bc7 bellard
    live = pcm_hw_get_live (hw);
65 85571bc7 bellard
    if (live <= 0)
66 85571bc7 bellard
        return;
67 85571bc7 bellard
68 7372f88d bellard
    wav->old_ticks = now;
69 85571bc7 bellard
    decr = audio_MIN (live, samples);
70 85571bc7 bellard
    samples = decr;
71 85571bc7 bellard
    rpos = hw->rpos;
72 85571bc7 bellard
    while (samples) {
73 85571bc7 bellard
        int left_till_end_samples = hw->samples - rpos;
74 85571bc7 bellard
        int convert_samples = audio_MIN (samples, left_till_end_samples);
75 85571bc7 bellard
76 85571bc7 bellard
        src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
77 85571bc7 bellard
        dst = advance (wav->pcm_buf, rpos << hw->shift);
78 85571bc7 bellard
79 85571bc7 bellard
        hw->clip (dst, src, convert_samples);
80 85571bc7 bellard
        qemu_put_buffer (wav->f, dst, convert_samples << hw->shift);
81 85571bc7 bellard
        memset (src, 0, convert_samples * sizeof (st_sample_t));
82 85571bc7 bellard
83 85571bc7 bellard
        rpos = (rpos + convert_samples) % hw->samples;
84 85571bc7 bellard
        samples -= convert_samples;
85 85571bc7 bellard
        wav->total_samples += convert_samples;
86 85571bc7 bellard
    }
87 85571bc7 bellard
88 85571bc7 bellard
    pcm_hw_dec_live (hw, decr);
89 85571bc7 bellard
    hw->rpos = rpos;
90 85571bc7 bellard
}
91 85571bc7 bellard
92 85571bc7 bellard
static int wav_hw_write (SWVoice *sw, void *buf, int len)
93 85571bc7 bellard
{
94 85571bc7 bellard
    return pcm_hw_write (sw, buf, len);
95 85571bc7 bellard
}
96 85571bc7 bellard
97 85571bc7 bellard
/* VICE code: Store number as little endian. */
98 85571bc7 bellard
static void le_store (uint8_t *buf, uint32_t val, int len)
99 85571bc7 bellard
{
100 85571bc7 bellard
    int i;
101 85571bc7 bellard
    for (i = 0; i < len; i++) {
102 85571bc7 bellard
        buf[i] = (uint8_t) (val & 0xff);
103 85571bc7 bellard
        val >>= 8;
104 85571bc7 bellard
    }
105 85571bc7 bellard
}
106 85571bc7 bellard
107 85571bc7 bellard
static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
108 85571bc7 bellard
{
109 85571bc7 bellard
    WAVVoice *wav = (WAVVoice *) hw;
110 85571bc7 bellard
    int bits16 = 0, stereo = audio_state.fixed_channels == 2;
111 85571bc7 bellard
    uint8_t hdr[] = {
112 85571bc7 bellard
        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
113 85571bc7 bellard
        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
114 85571bc7 bellard
        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
115 85571bc7 bellard
        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
116 85571bc7 bellard
    };
117 85571bc7 bellard
118 85571bc7 bellard
    switch (audio_state.fixed_fmt) {
119 85571bc7 bellard
    case AUD_FMT_S8:
120 85571bc7 bellard
    case AUD_FMT_U8:
121 85571bc7 bellard
        break;
122 85571bc7 bellard
123 85571bc7 bellard
    case AUD_FMT_S16:
124 85571bc7 bellard
    case AUD_FMT_U16:
125 85571bc7 bellard
        bits16 = 1;
126 85571bc7 bellard
        break;
127 85571bc7 bellard
    }
128 85571bc7 bellard
129 85571bc7 bellard
    hdr[34] = bits16 ? 0x10 : 0x08;
130 85571bc7 bellard
    hw->freq = 44100;
131 85571bc7 bellard
    hw->nchannels = stereo ? 2 : 1;
132 85571bc7 bellard
    hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
133 85571bc7 bellard
    hw->bufsize = 4096;
134 85571bc7 bellard
    wav->pcm_buf = qemu_mallocz (hw->bufsize);
135 85571bc7 bellard
    if (!wav->pcm_buf)
136 85571bc7 bellard
        return -1;
137 85571bc7 bellard
138 85571bc7 bellard
    le_store (hdr + 22, hw->nchannels, 2);
139 85571bc7 bellard
    le_store (hdr + 24, hw->freq, 4);
140 85571bc7 bellard
    le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);
141 85571bc7 bellard
    le_store (hdr + 32, 1 << (bits16 + stereo), 2);
142 85571bc7 bellard
143 85571bc7 bellard
    wav->f = fopen (conf.wav_path, "wb");
144 85571bc7 bellard
    if (!wav->f) {
145 85571bc7 bellard
        dolog ("failed to open wave file `%s'\nReason: %s\n",
146 85571bc7 bellard
               conf.wav_path, strerror (errno));
147 7372f88d bellard
        qemu_free (wav->pcm_buf);
148 7372f88d bellard
        wav->pcm_buf = NULL;
149 85571bc7 bellard
        return -1;
150 85571bc7 bellard
    }
151 85571bc7 bellard
152 85571bc7 bellard
    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
153 85571bc7 bellard
    return 0;
154 85571bc7 bellard
}
155 85571bc7 bellard
156 85571bc7 bellard
static void wav_hw_fini (HWVoice *hw)
157 85571bc7 bellard
{
158 85571bc7 bellard
    WAVVoice *wav = (WAVVoice *) hw;
159 85571bc7 bellard
    int stereo = hw->nchannels == 2;
160 85571bc7 bellard
    uint8_t rlen[4];
161 85571bc7 bellard
    uint8_t dlen[4];
162 85571bc7 bellard
    uint32_t rifflen = (wav->total_samples << stereo) + 36;
163 85571bc7 bellard
    uint32_t datalen = wav->total_samples << stereo;
164 85571bc7 bellard
165 85571bc7 bellard
    if (!wav->f || !hw->active)
166 85571bc7 bellard
        return;
167 85571bc7 bellard
168 85571bc7 bellard
    le_store (rlen, rifflen, 4);
169 85571bc7 bellard
    le_store (dlen, datalen, 4);
170 85571bc7 bellard
171 85571bc7 bellard
    qemu_fseek (wav->f, 4, SEEK_SET);
172 85571bc7 bellard
    qemu_put_buffer (wav->f, rlen, 4);
173 85571bc7 bellard
174 85571bc7 bellard
    qemu_fseek (wav->f, 32, SEEK_CUR);
175 85571bc7 bellard
    qemu_put_buffer (wav->f, dlen, 4);
176 85571bc7 bellard
177 85571bc7 bellard
    fclose (wav->f);
178 85571bc7 bellard
    wav->f = NULL;
179 7372f88d bellard
180 7372f88d bellard
    qemu_free (wav->pcm_buf);
181 7372f88d bellard
    wav->pcm_buf = NULL;
182 85571bc7 bellard
}
183 85571bc7 bellard
184 85571bc7 bellard
static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
185 85571bc7 bellard
{
186 85571bc7 bellard
    (void) hw;
187 85571bc7 bellard
    (void) cmd;
188 85571bc7 bellard
    return 0;
189 85571bc7 bellard
}
190 85571bc7 bellard
191 85571bc7 bellard
static void *wav_audio_init (void)
192 85571bc7 bellard
{
193 85571bc7 bellard
    return &conf;
194 85571bc7 bellard
}
195 85571bc7 bellard
196 85571bc7 bellard
static void wav_audio_fini (void *opaque)
197 85571bc7 bellard
{
198 85571bc7 bellard
    ldebug ("wav_fini");
199 85571bc7 bellard
}
200 85571bc7 bellard
201 85571bc7 bellard
struct pcm_ops wav_pcm_ops = {
202 85571bc7 bellard
    wav_hw_init,
203 85571bc7 bellard
    wav_hw_fini,
204 85571bc7 bellard
    wav_hw_run,
205 85571bc7 bellard
    wav_hw_write,
206 85571bc7 bellard
    wav_hw_ctl
207 85571bc7 bellard
};
208 85571bc7 bellard
209 85571bc7 bellard
struct audio_output_driver wav_output_driver = {
210 85571bc7 bellard
    "wav",
211 85571bc7 bellard
    wav_audio_init,
212 85571bc7 bellard
    wav_audio_fini,
213 85571bc7 bellard
    &wav_pcm_ops,
214 85571bc7 bellard
    1,
215 85571bc7 bellard
    1,
216 85571bc7 bellard
    sizeof (WAVVoice)
217 85571bc7 bellard
};