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