0.6.2-alt1.1
[qemu] / qemu-snapshot-2004-11-28_23 / 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
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 };