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