]> git.proxmox.com Git - qemu.git/blob - audio/wavaudio.c
audio clean up (initial patch by 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 #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 wav->old_ticks = now;
59
60 if (bytes > INT_MAX)
61 samples = INT_MAX >> hw->shift;
62 else
63 samples = bytes >> hw->shift;
64
65 live = pcm_hw_get_live (hw);
66 if (live <= 0)
67 return;
68
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
98 /* VICE code: Store number as little endian. */
99 static void le_store (uint8_t *buf, uint32_t val, int len)
100 {
101 int i;
102 for (i = 0; i < len; i++) {
103 buf[i] = (uint8_t) (val & 0xff);
104 val >>= 8;
105 }
106 }
107
108 static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
109 {
110 WAVVoice *wav = (WAVVoice *) hw;
111 int bits16 = 0, stereo = audio_state.fixed_channels == 2;
112 uint8_t hdr[] = {
113 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
114 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
115 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
116 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
117 };
118
119 switch (audio_state.fixed_fmt) {
120 case AUD_FMT_S8:
121 case AUD_FMT_U8:
122 break;
123
124 case AUD_FMT_S16:
125 case AUD_FMT_U16:
126 bits16 = 1;
127 break;
128 }
129
130 hdr[34] = bits16 ? 0x10 : 0x08;
131 hw->freq = 44100;
132 hw->nchannels = stereo ? 2 : 1;
133 hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
134 hw->bufsize = 4096;
135 wav->pcm_buf = qemu_mallocz (hw->bufsize);
136 if (!wav->pcm_buf)
137 return -1;
138
139 le_store (hdr + 22, hw->nchannels, 2);
140 le_store (hdr + 24, hw->freq, 4);
141 le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);
142 le_store (hdr + 32, 1 << (bits16 + stereo), 2);
143
144 wav->f = fopen (conf.wav_path, "wb");
145 if (!wav->f) {
146 dolog ("failed to open wave file `%s'\nReason: %s\n",
147 conf.wav_path, strerror (errno));
148 return -1;
149 }
150
151 qemu_put_buffer (wav->f, hdr, sizeof (hdr));
152 return 0;
153 }
154
155 static void wav_hw_fini (HWVoice *hw)
156 {
157 WAVVoice *wav = (WAVVoice *) hw;
158 int stereo = hw->nchannels == 2;
159 uint8_t rlen[4];
160 uint8_t dlen[4];
161 uint32_t rifflen = (wav->total_samples << stereo) + 36;
162 uint32_t datalen = wav->total_samples << stereo;
163
164 if (!wav->f || !hw->active)
165 return;
166
167 le_store (rlen, rifflen, 4);
168 le_store (dlen, datalen, 4);
169
170 qemu_fseek (wav->f, 4, SEEK_SET);
171 qemu_put_buffer (wav->f, rlen, 4);
172
173 qemu_fseek (wav->f, 32, SEEK_CUR);
174 qemu_put_buffer (wav->f, dlen, 4);
175
176 fclose (wav->f);
177 wav->f = NULL;
178 }
179
180 static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
181 {
182 (void) hw;
183 (void) cmd;
184 return 0;
185 }
186
187 static void *wav_audio_init (void)
188 {
189 return &conf;
190 }
191
192 static void wav_audio_fini (void *opaque)
193 {
194 ldebug ("wav_fini");
195 }
196
197 struct pcm_ops wav_pcm_ops = {
198 wav_hw_init,
199 wav_hw_fini,
200 wav_hw_run,
201 wav_hw_write,
202 wav_hw_ctl
203 };
204
205 struct audio_output_driver wav_output_driver = {
206 "wav",
207 wav_audio_init,
208 wav_audio_fini,
209 &wav_pcm_ops,
210 1,
211 1,
212 sizeof (WAVVoice)
213 };