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