Statistics
| Branch: | Revision:

root / hw / audio / adlib.c @ 36cd6f6f

History | View | Annotate | Download (8.6 kB)

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

    
25
#include "hw/hw.h"
26
#include "hw/audio/audio.h"
27
#include "audio/audio.h"
28
#include "hw/isa/isa.h"
29

    
30
//#define DEBUG
31

    
32
#define ADLIB_KILL_TIMERS 1
33

    
34
#ifdef HAS_YMF262
35
#define ADLIB_DESC "Yamaha YMF262 (OPL3)"
36
#else
37
#define ADLIB_DESC "Yamaha YM3812 (OPL2)"
38
#endif
39

    
40
#ifdef DEBUG
41
#include "qemu/timer.h"
42
#endif
43

    
44
#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
45
#ifdef DEBUG
46
#define ldebug(...) dolog (__VA_ARGS__)
47
#else
48
#define ldebug(...)
49
#endif
50

    
51
#ifdef HAS_YMF262
52
#include "ymf262.h"
53
void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
54
#define SHIFT 2
55
#else
56
#include "fmopl.h"
57
#define SHIFT 1
58
#endif
59

    
60
#define IO_READ_PROTO(name) \
61
    uint32_t name (void *opaque, uint32_t nport)
62
#define IO_WRITE_PROTO(name) \
63
    void name (void *opaque, uint32_t nport, uint32_t val)
64

    
65
#define TYPE_ADLIB "adlib"
66
#define ADLIB(obj) OBJECT_CHECK(AdlibState, (obj), TYPE_ADLIB)
67

    
68
typedef struct {
69
    ISADevice parent_obj;
70

    
71
    QEMUSoundCard card;
72
    uint32_t freq;
73
    uint32_t port;
74
    int ticking[2];
75
    int enabled;
76
    int active;
77
    int bufpos;
78
#ifdef DEBUG
79
    int64_t exp[2];
80
#endif
81
    int16_t *mixbuf;
82
    uint64_t dexp[2];
83
    SWVoiceOut *voice;
84
    int left, pos, samples;
85
    QEMUAudioTimeStamp ats;
86
#ifndef HAS_YMF262
87
    FM_OPL *opl;
88
#endif
89
} AdlibState;
90

    
91
static AdlibState *glob_adlib;
92

    
93
static void adlib_stop_opl_timer (AdlibState *s, size_t n)
94
{
95
#ifdef HAS_YMF262
96
    YMF262TimerOver (0, n);
97
#else
98
    OPLTimerOver (s->opl, n);
99
#endif
100
    s->ticking[n] = 0;
101
}
102

    
103
static void adlib_kill_timers (AdlibState *s)
104
{
105
    size_t i;
106

    
107
    for (i = 0; i < 2; ++i) {
108
        if (s->ticking[i]) {
109
            uint64_t delta;
110

    
111
            delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
112
            ldebug (
113
                "delta = %f dexp = %f expired => %d\n",
114
                delta / 1000000.0,
115
                s->dexp[i] / 1000000.0,
116
                delta >= s->dexp[i]
117
                );
118
            if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
119
                adlib_stop_opl_timer (s, i);
120
                AUD_init_time_stamp_out (s->voice, &s->ats);
121
            }
122
        }
123
    }
124
}
125

    
126
static IO_WRITE_PROTO (adlib_write)
127
{
128
    AdlibState *s = opaque;
129
    int a = nport & 3;
130

    
131
    s->active = 1;
132
    AUD_set_active_out (s->voice, 1);
133

    
134
    adlib_kill_timers (s);
135

    
136
#ifdef HAS_YMF262
137
    YMF262Write (0, a, val);
138
#else
139
    OPLWrite (s->opl, a, val);
140
#endif
141
}
142

    
143
static IO_READ_PROTO (adlib_read)
144
{
145
    AdlibState *s = opaque;
146
    uint8_t data;
147
    int a = nport & 3;
148

    
149
    adlib_kill_timers (s);
150

    
151
#ifdef HAS_YMF262
152
    data = YMF262Read (0, a);
153
#else
154
    data = OPLRead (s->opl, a);
155
#endif
156
    return data;
157
}
158

    
159
static void timer_handler (int c, double interval_Sec)
160
{
161
    AdlibState *s = glob_adlib;
162
    unsigned n = c & 1;
163
#ifdef DEBUG
164
    double interval;
165
    int64_t exp;
166
#endif
167

    
168
    if (interval_Sec == 0.0) {
169
        s->ticking[n] = 0;
170
        return;
171
    }
172

    
173
    s->ticking[n] = 1;
174
#ifdef DEBUG
175
    interval = get_ticks_per_sec () * interval_Sec;
176
    exp = qemu_get_clock_ns (vm_clock) + interval;
177
    s->exp[n] = exp;
178
#endif
179

    
180
    s->dexp[n] = interval_Sec * 1000000.0;
181
    AUD_init_time_stamp_out (s->voice, &s->ats);
182
}
183

    
184
static int write_audio (AdlibState *s, int samples)
185
{
186
    int net = 0;
187
    int pos = s->pos;
188

    
189
    while (samples) {
190
        int nbytes, wbytes, wsampl;
191

    
192
        nbytes = samples << SHIFT;
193
        wbytes = AUD_write (
194
            s->voice,
195
            s->mixbuf + (pos << (SHIFT - 1)),
196
            nbytes
197
            );
198

    
199
        if (wbytes) {
200
            wsampl = wbytes >> SHIFT;
201

    
202
            samples -= wsampl;
203
            pos = (pos + wsampl) % s->samples;
204

    
205
            net += wsampl;
206
        }
207
        else {
208
            break;
209
        }
210
    }
211

    
212
    return net;
213
}
214

    
215
static void adlib_callback (void *opaque, int free)
216
{
217
    AdlibState *s = opaque;
218
    int samples, net = 0, to_play, written;
219

    
220
    samples = free >> SHIFT;
221
    if (!(s->active && s->enabled) || !samples) {
222
        return;
223
    }
224

    
225
    to_play = audio_MIN (s->left, samples);
226
    while (to_play) {
227
        written = write_audio (s, to_play);
228

    
229
        if (written) {
230
            s->left -= written;
231
            samples -= written;
232
            to_play -= written;
233
            s->pos = (s->pos + written) % s->samples;
234
        }
235
        else {
236
            return;
237
        }
238
    }
239

    
240
    samples = audio_MIN (samples, s->samples - s->pos);
241
    if (!samples) {
242
        return;
243
    }
244

    
245
#ifdef HAS_YMF262
246
    YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
247
#else
248
    YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
249
#endif
250

    
251
    while (samples) {
252
        written = write_audio (s, samples);
253

    
254
        if (written) {
255
            net += written;
256
            samples -= written;
257
            s->pos = (s->pos + written) % s->samples;
258
        }
259
        else {
260
            s->left = samples;
261
            return;
262
        }
263
    }
264
}
265

    
266
static void Adlib_fini (AdlibState *s)
267
{
268
#ifdef HAS_YMF262
269
    YMF262Shutdown ();
270
#else
271
    if (s->opl) {
272
        OPLDestroy (s->opl);
273
        s->opl = NULL;
274
    }
275
#endif
276

    
277
    if (s->mixbuf) {
278
        g_free (s->mixbuf);
279
    }
280

    
281
    s->active = 0;
282
    s->enabled = 0;
283
    AUD_remove_card (&s->card);
284
}
285

    
286
static int Adlib_initfn (ISADevice *dev)
287
{
288
    AdlibState *s = ADLIB(dev);
289
    struct audsettings as;
290

    
291
    if (glob_adlib) {
292
        dolog ("Cannot create more than 1 adlib device\n");
293
        return -1;
294
    }
295
    glob_adlib = s;
296

    
297
#ifdef HAS_YMF262
298
    if (YMF262Init (1, 14318180, s->freq)) {
299
        dolog ("YMF262Init %d failed\n", s->freq);
300
        return -1;
301
    }
302
    else {
303
        YMF262SetTimerHandler (0, timer_handler, 0);
304
        s->enabled = 1;
305
    }
306
#else
307
    s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, s->freq);
308
    if (!s->opl) {
309
        dolog ("OPLCreate %d failed\n", s->freq);
310
        return -1;
311
    }
312
    else {
313
        OPLSetTimerHandler (s->opl, timer_handler, 0);
314
        s->enabled = 1;
315
    }
316
#endif
317

    
318
    as.freq = s->freq;
319
    as.nchannels = SHIFT;
320
    as.fmt = AUD_FMT_S16;
321
    as.endianness = AUDIO_HOST_ENDIANNESS;
322

    
323
    AUD_register_card ("adlib", &s->card);
324

    
325
    s->voice = AUD_open_out (
326
        &s->card,
327
        s->voice,
328
        "adlib",
329
        s,
330
        adlib_callback,
331
        &as
332
        );
333
    if (!s->voice) {
334
        Adlib_fini (s);
335
        return -1;
336
    }
337

    
338
    s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
339
    s->mixbuf = g_malloc0 (s->samples << SHIFT);
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 (s->port, 4, 1, adlib_read, s);
345
    register_ioport_write (s->port, 4, 1, adlib_write, s);
346

    
347
    register_ioport_read (s->port + 8, 2, 1, adlib_read, s);
348
    register_ioport_write (s->port + 8, 2, 1, adlib_write, s);
349

    
350
    return 0;
351
}
352

    
353
static Property adlib_properties[] = {
354
    DEFINE_PROP_HEX32  ("iobase",  AdlibState, port, 0x220),
355
    DEFINE_PROP_UINT32 ("freq",    AdlibState, freq,  44100),
356
    DEFINE_PROP_END_OF_LIST (),
357
};
358

    
359
static void adlib_class_initfn (ObjectClass *klass, void *data)
360
{
361
    DeviceClass *dc = DEVICE_CLASS (klass);
362
    ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
363
    ic->init = Adlib_initfn;
364
    dc->desc = ADLIB_DESC;
365
    dc->props = adlib_properties;
366
}
367

    
368
static const TypeInfo adlib_info = {
369
    .name          = TYPE_ADLIB,
370
    .parent        = TYPE_ISA_DEVICE,
371
    .instance_size = sizeof (AdlibState),
372
    .class_init    = adlib_class_initfn,
373
};
374

    
375
static int Adlib_init (ISABus *bus)
376
{
377
    isa_create_simple (bus, TYPE_ADLIB);
378
    return 0;
379
}
380

    
381
static void adlib_register_types (void)
382
{
383
    type_register_static (&adlib_info);
384
    isa_register_soundhw("adlib", ADLIB_DESC, Adlib_init);
385
}
386

    
387
type_init (adlib_register_types)