ia64/xen-unstable

view tools/ioemu/hw/adlib.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 8e5fc5fe636c
children f7b43e5c42b9
line source
1 /*
2 * QEMU Adlib emulation
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"
26 #define dolog(...) AUD_log ("adlib", __VA_ARGS__)
27 #ifdef DEBUG
28 #define ldebug(...) dolog (__VA_ARGS__)
29 #else
30 #define ldebug(...)
31 #endif
33 #ifdef USE_YMF262
34 #define HAS_YMF262 1
35 #include "ymf262.h"
36 void YMF262UpdateOneQEMU(int which, INT16 *dst, int length);
37 #define SHIFT 2
38 #else
39 #include "fmopl.h"
40 #define SHIFT 1
41 #endif
43 #ifdef _WIN32
44 #include <windows.h>
45 #define small_delay() Sleep (1)
46 #else
47 #define small_delay() usleep (1)
48 #endif
50 #define IO_READ_PROTO(name) \
51 uint32_t name (void *opaque, uint32_t nport)
52 #define IO_WRITE_PROTO(name) \
53 void name (void *opaque, uint32_t nport, uint32_t val)
55 static struct {
56 int port;
57 int freq;
58 } conf = {0x220, 44100};
60 typedef struct {
61 int enabled;
62 int active;
63 int cparam;
64 int64_t ticks;
65 int bufpos;
66 int16_t *mixbuf;
67 double interval;
68 QEMUTimer *ts, *opl_ts;
69 SWVoice *voice;
70 int left, pos, samples, bytes_per_second, old_free;
71 int refcount;
72 #ifndef USE_YMF262
73 FM_OPL *opl;
74 #endif
75 } AdlibState;
77 static AdlibState adlib;
79 static IO_WRITE_PROTO(adlib_write)
80 {
81 AdlibState *s = opaque;
82 int a = nport & 3;
83 int status;
85 s->ticks = qemu_get_clock (vm_clock);
86 s->active = 1;
87 AUD_enable (s->voice, 1);
89 #ifdef USE_YMF262
90 status = YMF262Write (0, a, val);
91 #else
92 status = OPLWrite (s->opl, a, val);
93 #endif
94 }
96 static IO_READ_PROTO(adlib_read)
97 {
98 AdlibState *s = opaque;
99 uint8_t data;
100 int a = nport & 3;
102 #ifdef USE_YMF262
103 (void) s;
104 data = YMF262Read (0, a);
105 #else
106 data = OPLRead (s->opl, a);
107 #endif
108 return data;
109 }
111 static void OPL_timer (void *opaque)
112 {
113 AdlibState *s = opaque;
114 #ifdef USE_YMF262
115 YMF262TimerOver (s->cparam >> 1, s->cparam & 1);
116 #else
117 OPLTimerOver (s->opl, s->cparam);
118 #endif
119 qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
120 }
122 static void YMF262TimerHandler (int c, double interval_Sec)
123 {
124 AdlibState *s = &adlib;
125 if (interval_Sec == 0.0) {
126 qemu_del_timer (s->opl_ts);
127 return;
128 }
129 s->cparam = c;
130 s->interval = ticks_per_sec * interval_Sec;
131 qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
132 small_delay ();
133 }
135 static int write_audio (AdlibState *s, int samples)
136 {
137 int net = 0;
138 int ss = samples;
139 while (samples) {
140 int nbytes = samples << SHIFT;
141 int wbytes = AUD_write (s->voice,
142 s->mixbuf + (s->pos << (SHIFT - 1)),
143 nbytes);
144 int wsampl = wbytes >> SHIFT;
145 samples -= wsampl;
146 s->pos = (s->pos + wsampl) % s->samples;
147 net += wsampl;
148 if (!wbytes)
149 break;
150 }
151 if (net > ss) {
152 dolog ("WARNING: net > ss\n");
153 }
154 return net;
155 }
157 static void timer (void *opaque)
158 {
159 AdlibState *s = opaque;
160 int elapsed, samples, net = 0;
162 if (s->refcount)
163 dolog ("refcount=%d\n", s->refcount);
165 s->refcount += 1;
166 if (!(s->active && s->enabled))
167 goto reset;
169 AUD_run ();
171 while (s->left) {
172 int written = write_audio (s, s->left);
173 net += written;
174 if (!written)
175 goto reset2;
176 s->left -= written;
177 }
178 s->pos = 0;
180 elapsed = AUD_calc_elapsed (s->voice);
181 if (!elapsed)
182 goto reset2;
184 /* elapsed = AUD_get_free (s->voice); */
185 samples = elapsed >> SHIFT;
186 if (!samples)
187 goto reset2;
189 samples = audio_MIN (samples, s->samples - s->pos);
190 if (s->left)
191 dolog ("left=%d samples=%d elapsed=%d free=%d\n",
192 s->left, samples, elapsed, AUD_get_free (s->voice));
194 if (!samples)
195 goto reset2;
197 #ifdef USE_YMF262
198 YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
199 #else
200 YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
201 #endif
203 while (samples) {
204 int written = write_audio (s, samples);
205 net += written;
206 if (!written)
207 break;
208 samples -= written;
209 }
210 if (!samples)
211 s->pos = 0;
212 s->left = samples;
214 reset2:
215 AUD_adjust (s->voice, net << SHIFT);
216 reset:
217 qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + ticks_per_sec / 1024);
218 s->refcount -= 1;
219 }
221 static void Adlib_fini (AdlibState *s)
222 {
223 #ifdef USE_YMF262
224 YMF262Shutdown ();
225 #else
226 if (s->opl) {
227 OPLDestroy (s->opl);
228 s->opl = NULL;
229 }
230 #endif
232 if (s->opl_ts)
233 qemu_free_timer (s->opl_ts);
235 if (s->ts)
236 qemu_free_timer (s->ts);
238 #define maybe_free(p) if (p) qemu_free (p)
239 maybe_free (s->mixbuf);
240 #undef maybe_free
242 s->active = 0;
243 s->enabled = 0;
244 }
246 void Adlib_init (void)
247 {
248 AdlibState *s = &adlib;
250 memset (s, 0, sizeof (*s));
252 #ifdef USE_YMF262
253 if (YMF262Init (1, 14318180, conf.freq)) {
254 dolog ("YMF262Init %d failed\n", conf.freq);
255 return;
256 }
257 else {
258 YMF262SetTimerHandler (0, YMF262TimerHandler, 0);
259 s->enabled = 1;
260 }
261 #else
262 s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
263 if (!s->opl) {
264 dolog ("OPLCreate %d failed\n", conf.freq);
265 return;
266 }
267 else {
268 OPLSetTimerHandler (s->opl, YMF262TimerHandler, 0);
269 s->enabled = 1;
270 }
271 #endif
273 s->opl_ts = qemu_new_timer (vm_clock, OPL_timer, s);
274 if (!s->opl_ts) {
275 dolog ("Can not get timer for adlib emulation\n");
276 Adlib_fini (s);
277 return;
278 }
280 s->ts = qemu_new_timer (vm_clock, timer, s);
281 if (!s->opl_ts) {
282 dolog ("Can not get timer for adlib emulation\n");
283 Adlib_fini (s);
284 return;
285 }
287 s->voice = AUD_open (s->voice, "adlib", conf.freq, SHIFT, AUD_FMT_S16);
288 if (!s->voice) {
289 Adlib_fini (s);
290 return;
291 }
293 s->bytes_per_second = conf.freq << SHIFT;
294 s->samples = AUD_get_buffer_size (s->voice) >> SHIFT;
295 s->mixbuf = qemu_mallocz (s->samples << SHIFT);
297 if (!s->mixbuf) {
298 dolog ("not enough memory for adlib mixing buffer (%d)\n",
299 s->samples << SHIFT);
300 Adlib_fini (s);
301 return;
302 }
303 register_ioport_read (0x388, 4, 1, adlib_read, s);
304 register_ioport_write (0x388, 4, 1, adlib_write, s);
306 register_ioport_read (conf.port, 4, 1, adlib_read, s);
307 register_ioport_write (conf.port, 4, 1, adlib_write, s);
309 register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
310 register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
312 qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
313 }