1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25: #include <assert.h>
26: #include "hw.h"
27: #include "audiodev.h"
28: #include "audio/audio.h"
29: #include "isa.h"
30:
31:
32:
33: #define ADLIB_KILL_TIMERS 1
34:
35: #ifdef DEBUG
36: #include "qemu-timer.h"
37: #endif
38:
39: #define dolog(...) AUD_log ("adlib", __VA_ARGS__)
40: #ifdef DEBUG
41: #define ldebug(...) dolog (__VA_ARGS__)
42: #else
43: #define ldebug(...)
44: #endif
45:
46: #ifdef HAS_YMF262
47: #include "ymf262.h"
48: void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
49: #define SHIFT 2
50: #else
51: #include "fmopl.h"
52: #define SHIFT 1
53: #endif
54:
55: #define IO_READ_PROTO(name) \
56: uint32_t name (void *opaque, uint32_t nport)
57: #define IO_WRITE_PROTO(name) \
58: void name (void *opaque, uint32_t nport, uint32_t val)
59:
60: static struct {
61: int port;
62: int freq;
63: } conf = {0x220, 44100};
64:
65: typedef struct {
66: QEMUSoundCard card;
67: int ticking[2];
68: int enabled;
69: int active;
70: int bufpos;
71: #ifdef DEBUG
72: int64_t exp[2];
73: #endif
74: int16_t *mixbuf;
75: uint64_t dexp[2];
76: SWVoiceOut *voice;
77: int left, pos, samples;
78: QEMUAudioTimeStamp ats;
79: #ifndef HAS_YMF262
80: FM_OPL *opl;
81: #endif
82: } AdlibState;
83:
84: static AdlibState glob_adlib;
85:
86: static void adlib_stop_opl_timer (AdlibState *s, size_t n)
87: {
88: #ifdef HAS_YMF262
89: YMF262TimerOver (0, n);
90: #else
91: OPLTimerOver (s->opl, n);
92: #endif
93: s->ticking[n] = 0;
94: }
95:
96: static void adlib_kill_timers (AdlibState *s)
97: {
98: size_t i;
99:
100: for (i = 0; i < 2; ++i) {
101: if (s->ticking[i]) {
102: uint64_t delta;
103:
104: delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
105: ldebug (
106: "delta = %f dexp = %f expired => %d\n",
107: delta / 1000000.0,
108: s->dexp[i] / 1000000.0,
109: delta >= s->dexp[i]
110: );
111: if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
112: adlib_stop_opl_timer (s, i);
113: AUD_init_time_stamp_out (s->voice, &s->ats);
114: }
115: }
116: }
117: }
118:
119: static IO_WRITE_PROTO(adlib_write)
120: {
121: AdlibState *s = opaque;
122: int a = nport & 3;
123: int status;
124:
125: s->active = 1;
126: AUD_set_active_out (s->voice, 1);
127:
128: adlib_kill_timers (s);
129:
130: #ifdef HAS_YMF262
131: status = YMF262Write (0, a, val);
132: #else
133: status = OPLWrite (s->opl, a, val);
134: #endif
135: }
136:
137: static IO_READ_PROTO(adlib_read)
138: {
139: AdlibState *s = opaque;
140: uint8_t data;
141: int a = nport & 3;
142:
143: adlib_kill_timers (s);
144:
145: #ifdef HAS_YMF262
146: data = YMF262Read (0, a);
147: #else
148: data = OPLRead (s->opl, a);
149: #endif
150: return data;
151: }
152:
153: static void timer_handler (int c, double interval_Sec)
154: {
155: AdlibState *s = &glob_adlib;
156: unsigned n = c & 1;
157: #ifdef DEBUG
158: double interval;
159: int64_t exp;
160: #endif
161:
162: if (interval_Sec == 0.0) {
163: s->ticking[n] = 0;
164: return;
165: }
166:
167: s->ticking[n] = 1;
168: #ifdef DEBUG
169: interval = ticks_per_sec * interval_Sec;
170: exp = qemu_get_clock (vm_clock) + interval;
171: s->exp[n] = exp;
172: #endif
173:
174: s->dexp[n] = interval_Sec * 1000000.0;
175: AUD_init_time_stamp_out (s->voice, &s->ats);
176: }
177:
178: static int write_audio (AdlibState *s, int samples)
179: {
180: int net = 0;
181: int pos = s->pos;
182:
183: while (samples) {
184: int nbytes, wbytes, wsampl;
185:
186: nbytes = samples << SHIFT;
187: wbytes = AUD_write (
188: s->voice,
189: s->mixbuf + (pos << (SHIFT - 1)),
190: nbytes
191: );
192:
193: if (wbytes) {
194: wsampl = wbytes >> SHIFT;
195:
196: samples -= wsampl;
197: pos = (pos + wsampl) % s->samples;
198:
199: net += wsampl;
200: }
201: else {
202: break;
203: }
204: }
205:
206: return net;
207: }
208:
209: static void adlib_callback (void *opaque, int free)
210: {
211: AdlibState *s = opaque;
212: int samples, net = 0, to_play, written;
213:
214: samples = free >> SHIFT;
215: if (!(s->active && s->enabled) || !samples) {
216: return;
217: }
218:
219: to_play = audio_MIN (s->left, samples);
220: while (to_play) {
221: written = write_audio (s, to_play);
222:
223: if (written) {
224: s->left -= written;
225: samples -= written;
226: to_play -= written;
227: s->pos = (s->pos + written) % s->samples;
228: }
229: else {
230: return;
231: }
232: }
233:
234: samples = audio_MIN (samples, s->samples - s->pos);
235: if (!samples) {
236: return;
237: }
238:
239: #ifdef HAS_YMF262
240: YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
241: #else
242: YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
243: #endif
244:
245: while (samples) {
246: written = write_audio (s, samples);
247:
248: if (written) {
249: net += written;
250: samples -= written;
251: s->pos = (s->pos + written) % s->samples;
252: }
253: else {
254: s->left = samples;
255: return;
256: }
257: }
258: }
259:
260: static void Adlib_fini (AdlibState *s)
261: {
262: #ifdef HAS_YMF262
263: YMF262Shutdown ();
264: #else
265: if (s->opl) {
266: OPLDestroy (s->opl);
267: s->opl = NULL;
268: }
269: #endif
270:
271: if (s->mixbuf) {
272: qemu_free (s->mixbuf);
273: }
274:
275: s->active = 0;
276: s->enabled = 0;
277: AUD_remove_card (&s->card);
278: }
279:
280: int Adlib_init (AudioState *audio, qemu_irq *pic)
281: {
282: AdlibState *s = &glob_adlib;
283: audsettings_t as;
284:
285: if (!audio) {
286: dolog ("No audio state\n");
287: return -1;
288: }
289:
290: #ifdef HAS_YMF262
291: if (YMF262Init (1, 14318180, conf.freq)) {
292: dolog ("YMF262Init %d failed\n", conf.freq);
293: return -1;
294: }
295: else {
296: YMF262SetTimerHandler (0, timer_handler, 0);
297: s->enabled = 1;
298: }
299: #else
300: s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
301: if (!s->opl) {
302: dolog ("OPLCreate %d failed\n", conf.freq);
303: return -1;
304: }
305: else {
306: OPLSetTimerHandler (s->opl, timer_handler, 0);
307: s->enabled = 1;
308: }
309: #endif
310:
311: as.freq = conf.freq;
312: as.nchannels = SHIFT;
313: as.fmt = AUD_FMT_S16;
314: as.endianness = AUDIO_HOST_ENDIANNESS;
315:
316: AUD_register_card (audio, "adlib", &s->card);
317:
318: s->voice = AUD_open_out (
319: &s->card,
320: s->voice,
321: "adlib",
322: s,
323: adlib_callback,
324: &as
325: );
326: if (!s->voice) {
327: Adlib_fini (s);
328: return -1;
329: }
330:
331: s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
332: s->mixbuf = qemu_mallocz (s->samples << SHIFT);
333:
334: if (!s->mixbuf) {
335: dolog ("Could not allocate mixing buffer, %d samples (each %d bytes)\n",
336: s->samples, 1 << SHIFT);
337: Adlib_fini (s);
338: return -1;
339: }
340:
341: register_ioport_read (0x388, 4, 1, adlib_read, s);
342: register_ioport_write (0x388, 4, 1, adlib_write, s);
343:
344: register_ioport_read (conf.port, 4, 1, adlib_read, s);
345: register_ioport_write (conf.port, 4, 1, adlib_write, s);
346:
347: register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
348: register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
349:
350: return 0;
351: }