xref: /qemu/audio/wavaudio.c (revision 9bb34eac)
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 };
201