]> git.proxmox.com Git - mirror_qemu.git/blame - audio/wavaudio.c
qemu-io-cmds: Assert that global and nofile commands don't use ct->perms
[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 */
6086a565 24#include "qemu/osdep.h"
87776ab7 25#include "qemu/host-utils.h"
1de7afc9 26#include "qemu/timer.h"
87ecb68b 27#include "audio.h"
85571bc7 28
1d14ffa9
FB
29#define AUDIO_CAP "wav"
30#include "audio_int.h"
fb065187 31
1d14ffa9
FB
32typedef struct WAVVoiceOut {
33 HWVoiceOut hw;
27acf660 34 FILE *f;
fb065187
FB
35 int64_t old_ticks;
36 void *pcm_buf;
37 int total_samples;
1d14ffa9 38} WAVVoiceOut;
85571bc7 39
f2dcc6ce 40typedef struct {
1ea879e5 41 struct audsettings settings;
85571bc7 42 const char *wav_path;
f2dcc6ce 43} WAVConf;
85571bc7 44
bdff253c 45static int wav_run_out (HWVoiceOut *hw, int live)
85571bc7 46{
1d14ffa9 47 WAVVoiceOut *wav = (WAVVoiceOut *) hw;
bdff253c 48 int rpos, decr, samples;
85571bc7 49 uint8_t *dst;
1ea879e5 50 struct st_sample *src;
bc72ad67 51 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
85571bc7 52 int64_t ticks = now - wav->old_ticks;
4f4cc0ef 53 int64_t bytes =
73bcb24d 54 muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
85571bc7 55
1d14ffa9
FB
56 if (bytes > INT_MAX) {
57 samples = INT_MAX >> hw->info.shift;
58 }
59 else {
60 samples = bytes >> hw->info.shift;
61 }
85571bc7 62
7372f88d 63 wav->old_ticks = now;
85571bc7
FB
64 decr = audio_MIN (live, samples);
65 samples = decr;
66 rpos = hw->rpos;
67 while (samples) {
68 int left_till_end_samples = hw->samples - rpos;
69 int convert_samples = audio_MIN (samples, left_till_end_samples);
70
1d14ffa9
FB
71 src = hw->mix_buf + rpos;
72 dst = advance (wav->pcm_buf, rpos << hw->info.shift);
85571bc7
FB
73
74 hw->clip (dst, src, convert_samples);
27acf660
JQ
75 if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) {
76 dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n",
77 convert_samples << hw->info.shift, strerror (errno));
78 }
85571bc7
FB
79
80 rpos = (rpos + convert_samples) % hw->samples;
81 samples -= convert_samples;
82 wav->total_samples += convert_samples;
83 }
84
85571bc7 85 hw->rpos = rpos;
1d14ffa9 86 return decr;
85571bc7
FB
87}
88
1d14ffa9 89static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
85571bc7 90{
1d14ffa9 91 return audio_pcm_sw_write (sw, buf, len);
85571bc7
FB
92}
93
85571bc7
FB
94/* VICE code: Store number as little endian. */
95static void le_store (uint8_t *buf, uint32_t val, int len)
96{
97 int i;
98 for (i = 0; i < len; i++) {
99 buf[i] = (uint8_t) (val & 0xff);
100 val >>= 8;
101 }
102}
103
5706db1d
KZ
104static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
105 void *drv_opaque)
85571bc7 106{
1d14ffa9 107 WAVVoiceOut *wav = (WAVVoiceOut *) hw;
c0fe3827 108 int bits16 = 0, stereo = 0;
85571bc7
FB
109 uint8_t hdr[] = {
110 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
111 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
112 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
113 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
114 };
f2dcc6ce
KZ
115 WAVConf *conf = drv_opaque;
116 struct audsettings wav_as = conf->settings;
85571bc7 117
c0fe3827
FB
118 stereo = wav_as.nchannels == 2;
119 switch (wav_as.fmt) {
85571bc7
FB
120 case AUD_FMT_S8:
121 case AUD_FMT_U8:
1d14ffa9 122 bits16 = 0;
85571bc7
FB
123 break;
124
125 case AUD_FMT_S16:
126 case AUD_FMT_U16:
127 bits16 = 1;
128 break;
f941aa25
TS
129
130 case AUD_FMT_S32:
131 case AUD_FMT_U32:
132 dolog ("WAVE files can not handle 32bit formats\n");
133 return -1;
85571bc7
FB
134 }
135
136 hdr[34] = bits16 ? 0x10 : 0x08;
c0fe3827 137
d929eba5
FB
138 wav_as.endianness = 0;
139 audio_pcm_init_info (&hw->info, &wav_as);
c0fe3827
FB
140
141 hw->samples = 1024;
142 wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
1d14ffa9 143 if (!wav->pcm_buf) {
c0fe3827
FB
144 dolog ("Could not allocate buffer (%d bytes)\n",
145 hw->samples << hw->info.shift);
85571bc7 146 return -1;
1d14ffa9 147 }
85571bc7 148
1d14ffa9
FB
149 le_store (hdr + 22, hw->info.nchannels, 2);
150 le_store (hdr + 24, hw->info.freq, 4);
c0fe3827
FB
151 le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
152 le_store (hdr + 32, 1 << (bits16 + stereo), 2);
85571bc7 153
f2dcc6ce 154 wav->f = fopen (conf->wav_path, "wb");
85571bc7 155 if (!wav->f) {
1d14ffa9 156 dolog ("Failed to open wave file `%s'\nReason: %s\n",
f2dcc6ce 157 conf->wav_path, strerror (errno));
7267c094 158 g_free (wav->pcm_buf);
7372f88d 159 wav->pcm_buf = NULL;
85571bc7
FB
160 return -1;
161 }
162
27acf660
JQ
163 if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
164 dolog ("wav_init_out: failed to write header\nReason: %s\n",
165 strerror(errno));
166 return -1;
167 }
85571bc7
FB
168 return 0;
169}
170
1d14ffa9 171static void wav_fini_out (HWVoiceOut *hw)
85571bc7 172{
1d14ffa9 173 WAVVoiceOut *wav = (WAVVoiceOut *) hw;
85571bc7
FB
174 uint8_t rlen[4];
175 uint8_t dlen[4];
50903530
FB
176 uint32_t datalen = wav->total_samples << hw->info.shift;
177 uint32_t rifflen = datalen + 36;
85571bc7 178
c0fe3827 179 if (!wav->f) {
85571bc7 180 return;
1d14ffa9 181 }
85571bc7
FB
182
183 le_store (rlen, rifflen, 4);
184 le_store (dlen, datalen, 4);
185
27acf660
JQ
186 if (fseek (wav->f, 4, SEEK_SET)) {
187 dolog ("wav_fini_out: fseek to rlen failed\nReason: %s\n",
188 strerror(errno));
189 goto doclose;
190 }
191 if (fwrite (rlen, 4, 1, wav->f) != 1) {
192 dolog ("wav_fini_out: failed to write rlen\nReason: %s\n",
193 strerror (errno));
194 goto doclose;
195 }
196 if (fseek (wav->f, 32, SEEK_CUR)) {
197 dolog ("wav_fini_out: fseek to dlen failed\nReason: %s\n",
198 strerror (errno));
199 goto doclose;
200 }
201 if (fwrite (dlen, 4, 1, wav->f) != 1) {
202 dolog ("wav_fini_out: failed to write dlen\nReaons: %s\n",
203 strerror (errno));
204 goto doclose;
205 }
85571bc7 206
27acf660
JQ
207 doclose:
208 if (fclose (wav->f)) {
209 dolog ("wav_fini_out: fclose %p failed\nReason: %s\n",
210 wav->f, strerror (errno));
211 }
85571bc7 212 wav->f = NULL;
7372f88d 213
7267c094 214 g_free (wav->pcm_buf);
7372f88d 215 wav->pcm_buf = NULL;
85571bc7
FB
216}
217
1d14ffa9 218static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
85571bc7
FB
219{
220 (void) hw;
221 (void) cmd;
222 return 0;
223}
224
f2dcc6ce
KZ
225static WAVConf glob_conf = {
226 .settings.freq = 44100,
227 .settings.nchannels = 2,
228 .settings.fmt = AUD_FMT_S16,
229 .wav_path = "qemu.wav"
230};
231
85571bc7
FB
232static void *wav_audio_init (void)
233{
f2dcc6ce
KZ
234 WAVConf *conf = g_malloc(sizeof(WAVConf));
235 *conf = glob_conf;
236 return conf;
85571bc7
FB
237}
238
239static void wav_audio_fini (void *opaque)
240{
241 ldebug ("wav_fini");
f2dcc6ce 242 g_free(opaque);
85571bc7
FB
243}
244
8869defe 245static struct audio_option wav_options[] = {
98f9f48c 246 {
247 .name = "FREQUENCY",
248 .tag = AUD_OPT_INT,
f2dcc6ce 249 .valp = &glob_conf.settings.freq,
98f9f48c 250 .descr = "Frequency"
251 },
252 {
253 .name = "FORMAT",
254 .tag = AUD_OPT_FMT,
f2dcc6ce 255 .valp = &glob_conf.settings.fmt,
98f9f48c 256 .descr = "Format"
257 },
258 {
259 .name = "DAC_FIXED_CHANNELS",
260 .tag = AUD_OPT_INT,
f2dcc6ce 261 .valp = &glob_conf.settings.nchannels,
98f9f48c 262 .descr = "Number of channels (1 - mono, 2 - stereo)"
263 },
264 {
265 .name = "PATH",
266 .tag = AUD_OPT_STR,
f2dcc6ce 267 .valp = &glob_conf.wav_path,
98f9f48c 268 .descr = "Path to wave file"
269 },
2700efa3 270 { /* End of list */ }
1d14ffa9
FB
271};
272
35f4b58c 273static struct audio_pcm_ops wav_pcm_ops = {
1dd3e4d1
JQ
274 .init_out = wav_init_out,
275 .fini_out = wav_fini_out,
276 .run_out = wav_run_out,
277 .write = wav_write_out,
278 .ctl_out = wav_ctl_out,
85571bc7
FB
279};
280
1d14ffa9 281struct audio_driver wav_audio_driver = {
bee37f32
JQ
282 .name = "wav",
283 .descr = "WAV renderer http://wikipedia.org/wiki/WAV",
284 .options = wav_options,
285 .init = wav_audio_init,
286 .fini = wav_audio_fini,
98f9f48c 287 .pcm_ops = &wav_pcm_ops,
bee37f32
JQ
288 .can_be_default = 0,
289 .max_voices_out = 1,
290 .max_voices_in = 0,
291 .voice_size_out = sizeof (WAVVoiceOut),
292 .voice_size_in = 0
85571bc7 293};