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