Statistics
| Branch: | Revision:

root / audio / wavaudio.c @ 7372f88d

History | View | Annotate | Download (5.6 kB)

1
/*
2
 * QEMU WAV audio output driver
3
 * 
4
 * Copyright (c) 2004 Vassili Karpov (malc)
5
 * 
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "vl.h"
25

    
26
#include "audio/audio_int.h"
27

    
28
typedef struct WAVVoice {
29
    HWVoice hw;
30
    QEMUFile *f;
31
    int64_t old_ticks;
32
    void *pcm_buf;
33
    int total_samples;
34
} WAVVoice;
35

    
36
#define dolog(...) AUD_log ("wav", __VA_ARGS__)
37
#ifdef DEBUG
38
#define ldebug(...) dolog (__VA_ARGS__)
39
#else
40
#define ldebug(...)
41
#endif
42

    
43
static struct {
44
    const char *wav_path;
45
} conf = {
46
    .wav_path = "qemu.wav"
47
};
48

    
49
static void wav_hw_run (HWVoice *hw)
50
{
51
    WAVVoice *wav = (WAVVoice *) hw;
52
    int rpos, live, decr, samples;
53
    uint8_t *dst;
54
    st_sample_t *src;
55
    int64_t now = qemu_get_clock (vm_clock);
56
    int64_t ticks = now - wav->old_ticks;
57
    int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
58

    
59
    if (bytes > INT_MAX)
60
        samples = INT_MAX >> hw->shift;
61
    else
62
        samples = bytes >> hw->shift;
63

    
64
    live = pcm_hw_get_live (hw);
65
    if (live <= 0)
66
        return;
67

    
68
    wav->old_ticks = now;
69
    decr = audio_MIN (live, samples);
70
    samples = decr;
71
    rpos = hw->rpos;
72
    while (samples) {
73
        int left_till_end_samples = hw->samples - rpos;
74
        int convert_samples = audio_MIN (samples, left_till_end_samples);
75

    
76
        src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
77
        dst = advance (wav->pcm_buf, rpos << hw->shift);
78

    
79
        hw->clip (dst, src, convert_samples);
80
        qemu_put_buffer (wav->f, dst, convert_samples << hw->shift);
81
        memset (src, 0, convert_samples * sizeof (st_sample_t));
82

    
83
        rpos = (rpos + convert_samples) % hw->samples;
84
        samples -= convert_samples;
85
        wav->total_samples += convert_samples;
86
    }
87

    
88
    pcm_hw_dec_live (hw, decr);
89
    hw->rpos = rpos;
90
}
91

    
92
static int wav_hw_write (SWVoice *sw, void *buf, int len)
93
{
94
    return pcm_hw_write (sw, buf, len);
95
}
96

    
97
/* VICE code: Store number as little endian. */
98
static void le_store (uint8_t *buf, uint32_t val, int len)
99
{
100
    int i;
101
    for (i = 0; i < len; i++) {
102
        buf[i] = (uint8_t) (val & 0xff);
103
        val >>= 8;
104
    }
105
}
106

    
107
static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
108
{
109
    WAVVoice *wav = (WAVVoice *) hw;
110
    int bits16 = 0, stereo = audio_state.fixed_channels == 2;
111
    uint8_t hdr[] = {
112
        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
113
        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
114
        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
115
        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
116
    };
117

    
118
    switch (audio_state.fixed_fmt) {
119
    case AUD_FMT_S8:
120
    case AUD_FMT_U8:
121
        break;
122

    
123
    case AUD_FMT_S16:
124
    case AUD_FMT_U16:
125
        bits16 = 1;
126
        break;
127
    }
128

    
129
    hdr[34] = bits16 ? 0x10 : 0x08;
130
    hw->freq = 44100;
131
    hw->nchannels = stereo ? 2 : 1;
132
    hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
133
    hw->bufsize = 4096;
134
    wav->pcm_buf = qemu_mallocz (hw->bufsize);
135
    if (!wav->pcm_buf)
136
        return -1;
137

    
138
    le_store (hdr + 22, hw->nchannels, 2);
139
    le_store (hdr + 24, hw->freq, 4);
140
    le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);
141
    le_store (hdr + 32, 1 << (bits16 + stereo), 2);
142

    
143
    wav->f = fopen (conf.wav_path, "wb");
144
    if (!wav->f) {
145
        dolog ("failed to open wave file `%s'\nReason: %s\n",
146
               conf.wav_path, strerror (errno));
147
        qemu_free (wav->pcm_buf);
148
        wav->pcm_buf = NULL;
149
        return -1;
150
    }
151

    
152
    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
153
    return 0;
154
}
155

    
156
static void wav_hw_fini (HWVoice *hw)
157
{
158
    WAVVoice *wav = (WAVVoice *) hw;
159
    int stereo = hw->nchannels == 2;
160
    uint8_t rlen[4];
161
    uint8_t dlen[4];
162
    uint32_t rifflen = (wav->total_samples << stereo) + 36;
163
    uint32_t datalen = wav->total_samples << stereo;
164

    
165
    if (!wav->f || !hw->active)
166
        return;
167

    
168
    le_store (rlen, rifflen, 4);
169
    le_store (dlen, datalen, 4);
170

    
171
    qemu_fseek (wav->f, 4, SEEK_SET);
172
    qemu_put_buffer (wav->f, rlen, 4);
173

    
174
    qemu_fseek (wav->f, 32, SEEK_CUR);
175
    qemu_put_buffer (wav->f, dlen, 4);
176

    
177
    fclose (wav->f);
178
    wav->f = NULL;
179

    
180
    qemu_free (wav->pcm_buf);
181
    wav->pcm_buf = NULL;
182
}
183

    
184
static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
185
{
186
    (void) hw;
187
    (void) cmd;
188
    return 0;
189
}
190

    
191
static void *wav_audio_init (void)
192
{
193
    return &conf;
194
}
195

    
196
static void wav_audio_fini (void *opaque)
197
{
198
    ldebug ("wav_fini");
199
}
200

    
201
struct pcm_ops wav_pcm_ops = {
202
    wav_hw_init,
203
    wav_hw_fini,
204
    wav_hw_run,
205
    wav_hw_write,
206
    wav_hw_ctl
207
};
208

    
209
struct audio_output_driver wav_output_driver = {
210
    "wav",
211
    wav_audio_init,
212
    wav_audio_fini,
213
    &wav_pcm_ops,
214
    1,
215
    1,
216
    sizeof (WAVVoice)
217
};