|
|
1.1 root 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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.