OXYGENHUB
◆ main enhanced-x16-emulator / src / midi.c
37.8 KiB · C · last changed chore(): initial commit 25 days ago source blame history raw
1
// Commander X16 Emulator
2
// Copyright (c) 2024 MooingLemur
3
// All rights reserved. License: 2-clause BSD
4
5
#include <SDL.h>
6
#include <stdio.h>
7
#include <time.h>
8
#include "glue.h"
9
#include "midi.h"
10
#include "audio.h"
11
#include "endian.h"
12
13
#ifdef _WIN32
14
    #include <windows.h>
15
    #define LIBRARY_TYPE HMODULE
16
    #define LOAD_LIBRARY(name) LoadLibrary(name)
17
    #define GET_FUNCTION(lib, name) (void *)GetProcAddress(lib, name)
18
    #define CLOSE_LIBRARY(lib) FreeLibrary(lib)
19
#else
20
    #include <dlfcn.h>
21
    #define LIBRARY_TYPE void*
22
    #define LOAD_LIBRARY(name) dlopen(name, RTLD_LAZY)
23
    #define GET_FUNCTION(lib, name) dlsym(lib, name)
24
    #define CLOSE_LIBRARY(lib) dlclose(lib)
25
#endif
26
27
#define ASSIGN_FUNCTION(lib, var, name) {\
28
    var = GET_FUNCTION(lib, name);\
29
    if (!var) { fprintf(stderr, "Unable to find symbol for '%s'\n", name); CLOSE_LIBRARY(handle); return; }\
30
}
31
32
enum MIDI_states {
33
    MSTATE_Normal,
34
    MSTATE_Param,
35
    MSTATE_SysEx,
36
};
37
38
struct midi_serial_regs
39
{
40
    LOW_HIGH_UNION(dl, dll, dlm);
41
42
    bool ier_erbi;
43
    bool ier_etbei;
44
    bool ier_elsi;
45
    bool ier_edssi;
46
47
    uint8_t iir;
48
49
    bool fcr_fifo_enable;
50
    uint8_t fcr_ififo_trigger_level_bytes;
51
52
    uint8_t lcr_word_length_bits;
53
    bool lcr_stb;
54
    bool lcr_pen;
55
    bool lcr_eps;
56
    bool lcr_stick;
57
    bool lcr_break;
58
    bool lcr_dlab;
59
60
    bool mcr_dtr;
61
    bool mcr_rts;
62
    bool mcr_out1;
63
    bool mcr_out2;
64
    bool mcr_loop;
65
    bool mcr_afe;
66
67
    bool lsr_oe;
68
    bool lsr_pe;
69
    bool lsr_fe;
70
    bool lsr_bi;
71
    bool lsr_eif;
72
73
    bool msr_dcts;
74
    bool msr_ddsr;
75
    bool msr_teri;
76
    bool msr_ddcd;
77
    bool msr_cts;
78
    bool msr_dsr;
79
    bool msr_ri;
80
    bool msr_dcd;
81
82
    uint8_t obyte_bits_remain;
83
    uint8_t ibyte_bits_remain;
84
    uint8_t rx_timeout;
85
    bool rx_timeout_enabled;
86
87
    bool thre_intr;
88
    uint8_t thre_bits_remain;
89
90
    uint8_t scratch;
91
    uint8_t ififo[16];
92
    uint8_t ifsz;
93
    uint8_t ofifo[16];
94
    uint8_t ofsz;
95
96
    int64_t clock; // 40.24 fixed point
97
    int32_t clockdec; // 8.24 fixed point
98
99
    time_t last_warning;
100
101
    uint8_t midi_event_fifo[256];
102
    int mfsz;
103
    uint8_t in_midi_last_command;
104
105
    SDL_mutex *fifo_mutex;
106
};
107
108
struct midi_serial_regs mregs[2];
109
static bool serial_midi_mutexes_initialized = false;
110
111
void midi_serial_iir_check(uint8_t sel);
112
bool fs_midi_in_connect = false;
113
114
#ifdef HAS_FLUIDSYNTH
115
116
int handle_midi_event(void* data, fluid_midi_event_t* event);
117
118
static uint8_t sysex_buffer[1024];
119
static int sysex_bufptr;
120
121
static enum MIDI_states midi_state[2] = {MSTATE_Normal, MSTATE_Normal};
122
static uint8_t out_midi_last_command[2] = {0, 0};
123
static uint8_t out_midi_first_param[2];
124
static uint16_t out_midi_nrpn[2][16];
125
static uint16_t out_midi_rpn[2][16];
126
static bool out_midi_nrpn_active[2][16];
127
128
static bool midi_initialized = false;
129
130
static fluid_settings_t* fl_settings;
131
static fluid_midi_driver_t* fl_mdriver;
132
static fluid_synth_t* fl_synth;
133
static int fl_sf2id;
134
135
typedef fluid_settings_t* (*new_fluid_settings_f_t)(void);
136
typedef fluid_synth_t* (*new_fluid_synth_f_t)(fluid_settings_t*);
137
typedef fluid_audio_driver_t* (*new_fluid_audio_driver_f_t)(fluid_settings_t*, fluid_synth_t*);
138
typedef fluid_midi_driver_t* (*new_fluid_midi_driver_f_t)(fluid_settings_t*, handle_midi_event_func_t, void*);
139
typedef int (*fluid_settings_setnum_f_t)(fluid_settings_t*,const char*, double);
140
typedef int (*fluid_settings_setint_f_t)(fluid_settings_t*,const char*, int);
141
typedef int (*fluid_settings_setstr_f_t)(fluid_settings_t*,const char*, const char*);
142
typedef int (*fluid_synth_sfload_f_t)(fluid_synth_t*, const char *, int);
143
typedef int (*fluid_synth_program_change_f_t)(fluid_synth_t*, int, int);
144
typedef int (*fluid_synth_channel_pressure_f_t)(fluid_synth_t*, int, int);
145
typedef int (*fluid_synth_system_reset_f_t)(fluid_synth_t*);
146
typedef int (*fluid_synth_noteoff_f_t)(fluid_synth_t*, int, int);
147
typedef int (*fluid_synth_noteon_f_t)(fluid_synth_t*, int, int, int);
148
typedef int (*fluid_synth_key_pressure_f_t)(fluid_synth_t*, int, int, int);
149
typedef int (*fluid_synth_cc_f_t)(fluid_synth_t*, int, int, int);
150
typedef int (*fluid_synth_pitch_bend_f_t)(fluid_synth_t*, int, int);
151
typedef int (*fluid_synth_sysex_f_t)(fluid_synth_t*, const char*, int, char*, int*, int*, int);
152
typedef int (*fluid_synth_write_s16_f_t)(fluid_synth_t*, int, void*, int, int, void*, int, int);
153
typedef int (*fluid_midi_event_get_channel_f_t)(const fluid_midi_event_t*);
154
typedef int (*fluid_midi_event_get_control_f_t)(const fluid_midi_event_t*);
155
typedef int (*fluid_midi_event_get_key_f_t)(const fluid_midi_event_t*);
156
typedef int (*fluid_midi_event_get_lyrics_f_t)(const fluid_midi_event_t*, void**, int*);
157
typedef int (*fluid_midi_event_get_pitch_f_t)(const fluid_midi_event_t*);
158
typedef int (*fluid_midi_event_get_program_f_t)(const fluid_midi_event_t*);
159
typedef int (*fluid_midi_event_get_text_f_t)(const fluid_midi_event_t*, void**, int*);
160
typedef int (*fluid_midi_event_get_type_f_t)(const fluid_midi_event_t*);
161
typedef int (*fluid_midi_event_get_value_f_t)(const fluid_midi_event_t*);
162
typedef int (*fluid_midi_event_get_velocity_f_t)(const fluid_midi_event_t*);
163
typedef int (*fluid_midi_event_set_type_f_t)(fluid_midi_event_t*, int);
164
165
static new_fluid_settings_f_t dl_new_fluid_settings;
166
static new_fluid_synth_f_t dl_new_fluid_synth;
167
static new_fluid_audio_driver_f_t dl_new_fluid_audio_driver;
168
static new_fluid_midi_driver_f_t dl_new_fluid_midi_driver;
169
static fluid_settings_setnum_f_t dl_fluid_settings_setnum;
170
static fluid_settings_setint_f_t dl_fluid_settings_setint;
171
static fluid_settings_setstr_f_t dl_fluid_settings_setstr;
172
static fluid_synth_sfload_f_t dl_fs_sfload;
173
static fluid_synth_program_change_f_t dl_fs_program_change;
174
static fluid_synth_channel_pressure_f_t dl_fs_channel_pressure;
175
static fluid_synth_system_reset_f_t dl_fs_system_reset;
176
static fluid_synth_noteoff_f_t dl_fs_noteoff;
177
static fluid_synth_noteon_f_t dl_fs_noteon;
178
static fluid_synth_key_pressure_f_t dl_fs_key_pressure;
179
static fluid_synth_cc_f_t dl_fs_cc;
180
static fluid_synth_pitch_bend_f_t dl_fs_pitch_bend;
181
static fluid_synth_sysex_f_t dl_fs_sysex;
182
static fluid_synth_write_s16_f_t dl_fs_write_s16;
183
static fluid_midi_event_get_channel_f_t dl_fluid_midi_event_get_channel;
184
static fluid_midi_event_get_control_f_t dl_fluid_midi_event_get_control;
185
static fluid_midi_event_get_key_f_t dl_fluid_midi_event_get_key;
186
static fluid_midi_event_get_lyrics_f_t dl_fluid_midi_event_get_lyrics;
187
static fluid_midi_event_get_pitch_f_t dl_fluid_midi_event_get_pitch;
188
static fluid_midi_event_get_program_f_t dl_fluid_midi_event_get_program;
189
static fluid_midi_event_get_text_f_t dl_fluid_midi_event_get_text;
190
static fluid_midi_event_get_type_f_t dl_fluid_midi_event_get_type;
191
static fluid_midi_event_get_value_f_t dl_fluid_midi_event_get_value;
192
static fluid_midi_event_get_velocity_f_t dl_fluid_midi_event_get_velocity;
193
static fluid_midi_event_set_type_f_t dl_fluid_midi_event_set_type;
194
195
196
void midi_init()
197
{
198
    if (midi_initialized) {
199
        return;
200
    }
201
202
#ifdef _WIN32
203
    LIBRARY_TYPE handle = LOAD_LIBRARY("libfluidsynth-3.dll");
204
#elif __APPLE__
205
    LIBRARY_TYPE handle = LOAD_LIBRARY("libfluidsynth.dylib");
206
#else
207
    LIBRARY_TYPE handle = LOAD_LIBRARY("libfluidsynth.so.3");
208
#endif
209
210
    if (!handle) {
211
        // Handle the error on both platforms
212
#ifdef _WIN32
213
        fprintf(stderr, "Could not load MIDI synth library: error code %lu\n", GetLastError());
214
#else
215
        fprintf(stderr, "Could not load MIDI synth library: %s\n", dlerror());
216
#endif
217
        return;
218
    }
219
220
#ifndef _WIN32
221
    dlerror();
222
#endif
223
224
    ASSIGN_FUNCTION(handle, dl_new_fluid_settings, "new_fluid_settings");
225
    ASSIGN_FUNCTION(handle, dl_new_fluid_synth, "new_fluid_synth");
226
    ASSIGN_FUNCTION(handle, dl_new_fluid_audio_driver, "new_fluid_audio_driver");
227
    ASSIGN_FUNCTION(handle, dl_new_fluid_midi_driver, "new_fluid_midi_driver");
228
    ASSIGN_FUNCTION(handle, dl_fluid_settings_setnum, "fluid_settings_setnum");
229
    ASSIGN_FUNCTION(handle, dl_fluid_settings_setint, "fluid_settings_setint");
230
    ASSIGN_FUNCTION(handle, dl_fluid_settings_setstr, "fluid_settings_setstr");
231
    ASSIGN_FUNCTION(handle, dl_fs_sfload, "fluid_synth_sfload");
232
    ASSIGN_FUNCTION(handle, dl_fs_program_change, "fluid_synth_program_change");
233
    ASSIGN_FUNCTION(handle, dl_fs_channel_pressure, "fluid_synth_channel_pressure");
234
    ASSIGN_FUNCTION(handle, dl_fs_system_reset, "fluid_synth_system_reset");
235
    ASSIGN_FUNCTION(handle, dl_fs_noteoff, "fluid_synth_noteoff");
236
    ASSIGN_FUNCTION(handle, dl_fs_noteon, "fluid_synth_noteon");
237
    ASSIGN_FUNCTION(handle, dl_fs_key_pressure, "fluid_synth_key_pressure");
238
    ASSIGN_FUNCTION(handle, dl_fs_cc, "fluid_synth_cc");
239
    ASSIGN_FUNCTION(handle, dl_fs_pitch_bend, "fluid_synth_pitch_bend");
240
    ASSIGN_FUNCTION(handle, dl_fs_sysex, "fluid_synth_sysex");
241
    ASSIGN_FUNCTION(handle, dl_fs_write_s16, "fluid_synth_write_s16");
242
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_channel, "fluid_midi_event_get_channel");
243
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_control, "fluid_midi_event_get_control");
244
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_key, "fluid_midi_event_get_key");
245
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_lyrics, "fluid_midi_event_get_lyrics");
246
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_pitch, "fluid_midi_event_get_pitch");
247
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_program, "fluid_midi_event_get_program");
248
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_text, "fluid_midi_event_get_text");
249
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_type, "fluid_midi_event_get_type");
250
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_value, "fluid_midi_event_get_value");
251
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_get_velocity, "fluid_midi_event_get_velocity");
252
    ASSIGN_FUNCTION(handle, dl_fluid_midi_event_set_type, "fluid_midi_event_set_type");
253
254
    fl_settings = dl_new_fluid_settings();
255
    dl_fluid_settings_setnum(fl_settings, "synth.sample-rate", 
256
    AUDIO_SAMPLERATE);
257
    dl_fluid_settings_setnum(fl_settings, "synth.gain", FL_DEFAULT_GAIN);
258
    dl_fluid_settings_setstr(fl_settings, "midi.portname", "Commander X16 Emulator");
259
    dl_fluid_settings_setint(fl_settings, "midi.autoconnect", fs_midi_in_connect);
260
    fl_synth = dl_new_fluid_synth(fl_settings);
261
    if (fs_midi_in_connect) {
262
        fl_mdriver = dl_new_fluid_midi_driver(fl_settings, handle_midi_event, &mregs[0]);
263
    }
264
265
    midi_initialized = true;
266
    fprintf(stderr, "Initialized MIDI synth at $%04X.\n", midi_card_addr);
267
}
268
269
void midi_load_sf2(uint8_t* filename)
270
{
271
    if (!midi_initialized) return;
272
    fl_sf2id = dl_fs_sfload(fl_synth, (const char *)filename, true);
273
    if (fl_sf2id == FLUID_FAILED) {
274
        fprintf(stderr, "Unable to load soundfont.\n");
275
    }
276
}
277
278
// Receive a byte from client
279
// Store state, or dispatch event
280
void midi_byte_out(uint8_t sel, uint8_t b)
281
{
282
    uint8_t chan = out_midi_last_command[sel] & 0xf;
283
284
    if (!midi_initialized) return;
285
    switch (midi_state[sel]) {
286
        case MSTATE_Normal:
287
            if (b < 0x80) {
288
                if ((out_midi_last_command[sel] & 0xf0) == 0xc0) { // patch change
289
                    dl_fs_program_change(fl_synth, out_midi_last_command[sel] & 0xf, b);
290
                } else if ((out_midi_last_command[sel] & 0xf0) == 0xd0) { // channel pressure
291
                    dl_fs_channel_pressure(fl_synth, out_midi_last_command[sel] & 0xf, b);
292
                } else if (out_midi_last_command[sel] >= 0x80) { // two-param command
293
                    out_midi_first_param[sel] = b;
294
                    midi_state[sel] = MSTATE_Param;
295
                }
296
            } else {
297
                if (b < 0xf0) {
298
                    out_midi_last_command[sel] = b;
299
                } else if (b == 0xf0) {
300
                    sysex_bufptr = 0;
301
                    midi_state[sel] = MSTATE_SysEx;
302
                    out_midi_last_command[sel] = 0;
303
                } else if (b == 0xff) {
304
                    dl_fs_system_reset(fl_synth);
305
                    out_midi_last_command[sel] = 0;
306
                } else if (b < 0xf8) {
307
                    out_midi_last_command[sel] = 0;
308
                }
309
            }
310
            break;
311
        case MSTATE_Param:
312
            switch (out_midi_last_command[sel] & 0xf0) {
313
                case 0x80: // note off
314
                    dl_fs_noteoff(fl_synth, chan, out_midi_first_param[sel]); // no release velocity
315
                    break;
316
                case 0x90: // note on
317
                    if (b == 0) {
318
                        dl_fs_noteoff(fl_synth, chan, out_midi_first_param[sel]);
319
                    } else {
320
                        dl_fs_noteon(fl_synth, chan, out_midi_first_param[sel], b);
321
                    }
322
                    break;
323
                case 0xa0: // aftertouch
324
                    dl_fs_key_pressure(fl_synth, chan, out_midi_first_param[sel], b);
325
                    break;
326
                case 0xb0: // controller
327
                    switch (out_midi_first_param[sel]) {
328
                        case 98:
329
                            out_midi_nrpn_active[sel][chan] = true;
330
                            out_midi_nrpn[sel][chan] = (out_midi_nrpn[sel][chan] & 0x00ff) | (b << 8);
331
                            break;
332
                        case 99:
333
                            out_midi_nrpn_active[sel][chan] = true;
334
                            out_midi_nrpn[sel][chan] = (out_midi_nrpn[sel][chan] & 0xff00) | b;
335
                            break;
336
                        case 100:
337
                            out_midi_nrpn_active[sel][chan] = false;
338
                            out_midi_rpn[sel][chan] = (out_midi_rpn[sel][chan] & 0x00ff) | (b << 8);
339
                            break;
340
                        case 101:
341
                            out_midi_nrpn_active[sel][chan] = false;
342
                            out_midi_rpn[sel][chan] = (out_midi_rpn[sel][chan] & 0xff00) | b;
343
                            break;
344
                    }
345
                    dl_fs_cc(fl_synth, chan, out_midi_first_param[sel], b);
346
                    if (out_midi_nrpn_active[sel][chan] && out_midi_nrpn[sel][chan] == 0x0121 && out_midi_first_param[sel] == 6) {
347
                        dl_fs_cc(fl_synth, chan, 71, b); // Translate NRPN 0x0121 -> Controller 71 (Timbre/Resonance)
348
                    }
349
                    break;
350
                case 0xe0: // pitch bend
351
                    dl_fs_pitch_bend(fl_synth, chan, ((uint16_t)out_midi_first_param[sel]) | (uint16_t)b << 7);
352
                    break;
353
            }
354
            midi_state[sel] = MSTATE_Normal;
355
            break;
356
        case MSTATE_SysEx:
357
            if (b & 0x80) { // any command byte can terminate a SYSEX, not just 0xf7
358
                if (sysex_bufptr < (sizeof(sysex_buffer) / sizeof(sysex_buffer[0]))-1) { // only if buffer didn't fill
359
                    sysex_buffer[sysex_bufptr] = 0;
360
                    if (!strncmp((char *)sysex_buffer, "\x7F\x7F\x04\x01\x00", sysex_bufptr-1)) {
361
                        // Handle Master Volume SysEx
362
                        dl_fluid_settings_setnum(fl_settings, "synth.gain", FL_DEFAULT_GAIN*((float)sysex_buffer[sysex_bufptr-1]/127));
363
                    } else if (!strncmp((char *)sysex_buffer, "\x7E\x7F\x09\x01", sysex_bufptr)) {
364
                        // Handle General MIDI reset SysEx
365
                        dl_fs_system_reset(fl_synth);
366
                    } else {
367
                        dl_fs_sysex(fl_synth, (char *)sysex_buffer, sysex_bufptr, NULL, NULL, NULL, 0);
368
                    }
369
                }
370
                midi_state[sel] = MSTATE_Normal;
371
                return midi_byte_out(sel, b);
372
            } else {
373
                sysex_buffer[sysex_bufptr] = b;
374
                // we can't do much about a runaway sysex other than continue to absorb it
375
                // but we throw it all away later if the buffer filled
376
                if (sysex_bufptr < (sizeof(sysex_buffer) / sizeof(sysex_buffer[0]))-1) {
377
                    sysex_bufptr++;
378
                }
379
            }
380
            break;
381
    }
382
}
383
384
void midi_synth_render(int16_t* buf, int len)
385
{
386
    if (midi_initialized) {
387
        dl_fs_write_s16(fl_synth, len, buf, 0, 2, buf, 1, 2);
388
    } else {
389
        memset(buf, 0, len * 2 * sizeof(int16_t));
390
    }
391
}
392
393
void midi_event_enqueue_byte(struct midi_serial_regs* mrp, uint8_t val)
394
{
395
    if (mrp->mfsz >= 256) return;
396
    mrp->midi_event_fifo[mrp->mfsz++] = val;
397
}
398
399
void midi_event_enqueue_short(struct midi_serial_regs* mrp, uint8_t cmd, uint8_t val)
400
{
401
    if (mrp->mfsz >= 255) {
402
        mrp->in_midi_last_command = 0;
403
        return;
404
    }
405
    if (mrp->in_midi_last_command != cmd) {
406
        mrp->midi_event_fifo[mrp->mfsz++] = cmd;
407
        mrp->in_midi_last_command = cmd;
408
    }
409
    mrp->midi_event_fifo[mrp->mfsz++] = val;
410
}
411
412
void midi_event_enqueue_normal(struct midi_serial_regs* mrp, uint8_t cmd, uint8_t key, uint8_t val)
413
{
414
    if (mrp->mfsz >= 254) {
415
        mrp->in_midi_last_command = 0;
416
        return;
417
    }
418
    if (mrp->in_midi_last_command != cmd) {
419
        mrp->midi_event_fifo[mrp->mfsz++] = cmd;
420
        mrp->in_midi_last_command = cmd;
421
    }
422
    mrp->midi_event_fifo[mrp->mfsz++] = key;
423
    mrp->midi_event_fifo[mrp->mfsz++] = val;
424
}
425
426
void midi_event_enqueue_sysex(struct midi_serial_regs* mrp, uint8_t *bufptr, int buflen)
427
{
428
    int i;
429
430
    mrp->in_midi_last_command = 0;
431
    if (mrp->mfsz >= 255L - (buflen + 2)) { // too full
432
        return;
433
    }
434
435
    mrp->midi_event_fifo[mrp->mfsz++] = 0xf0;
436
    for (i = 0; i < buflen; i++) {
437
        mrp->midi_event_fifo[mrp->mfsz++] = bufptr[i];
438
    }
439
    mrp->midi_event_fifo[mrp->mfsz++] = 0xf7;
440
}
441
442
int handle_midi_event(void* data, fluid_midi_event_t* event)
443
{
444
    struct midi_serial_regs* mrp = (struct midi_serial_regs*)data;
445
    SDL_LockMutex(mrp->fifo_mutex);
446
447
    uint8_t type = dl_fluid_midi_event_get_type(event);
448
    uint8_t chan = dl_fluid_midi_event_get_channel(event);
449
    uint8_t cmd = (type < 0x80 || type >= 0xf0) ? type : (type | (chan & 0xf));
450
    uint8_t key, val;
451
    uint8_t *bufptr;
452
    int buflen;
453
454
    switch (type) {
455
        case FS_NOTE_OFF:
456
        case FS_NOTE_ON:
457
            key = dl_fluid_midi_event_get_key(event);
458
            val = dl_fluid_midi_event_get_velocity(event);
459
            midi_event_enqueue_normal(mrp, cmd, key, val);
460
            break;
461
        case FS_KEY_PRESSURE:
462
            key = dl_fluid_midi_event_get_key(event);
463
            val = dl_fluid_midi_event_get_value(event);
464
            midi_event_enqueue_normal(mrp, cmd, key, val);
465
            break;
466
        case FS_CONTROL_CHANGE:
467
            key = dl_fluid_midi_event_get_control(event);
468
            val = dl_fluid_midi_event_get_value(event);
469
            midi_event_enqueue_normal(mrp, cmd, key, val);
470
            break;
471
        case FS_PITCH_BEND:
472
            key = dl_fluid_midi_event_get_pitch(event) & 0x7f;
473
            val = (dl_fluid_midi_event_get_pitch(event) >> 7) & 0x7f;
474
            midi_event_enqueue_normal(mrp, cmd, key, val);
475
            break;
476
        case FS_PROGRAM_CHANGE:
477
        case FS_CHANNEL_PRESSURE:
478
            val = dl_fluid_midi_event_get_program(event);
479
            midi_event_enqueue_short(mrp, cmd, val);
480
            break;
481
        case FS_MIDI_TIME_CODE:
482
            val = dl_fluid_midi_event_get_value(event);
483
            midi_event_enqueue_short(mrp, type, val);
484
            mrp->in_midi_last_command = 0;
485
            break;
486
        case FS_MIDI_TUNE_REQUEST:
487
        case 0xF4:
488
        case 0xF5:
489
            midi_event_enqueue_byte(mrp, type);
490
            mrp->in_midi_last_command = 0;
491
            break;
492
        case FS_MIDI_SYNC:
493
        case FS_MIDI_TICK:
494
        case FS_MIDI_START:
495
        case FS_MIDI_CONTINUE:
496
        case FS_MIDI_STOP:
497
        case FS_MIDI_ACTIVE_SENSING:
498
        case FS_MIDI_SYSTEM_RESET:
499
            midi_event_enqueue_byte(mrp, type);
500
            break;
501
        case FS_MIDI_SYSEX:
502
            // FluidSynth doesn't offer a get_sysex function, but internally
503
            // a text event is equivalent to a sysex event, in terms of what
504
            // parts of the event structure are populated
505
            //
506
            // Unfortunately that means we have to fool it in order to
507
            // access the data.
508
            dl_fluid_midi_event_set_type(event, FS_MIDI_TEXT);
509
            if (dl_fluid_midi_event_get_text(event, (void **)&bufptr, &buflen) == FLUID_OK && bufptr != NULL) {
510
                midi_event_enqueue_sysex(mrp, bufptr, buflen);
511
            }
512
            break;
513
    }
514
515
    //fprintf(stderr, "Debug: MIDI IN: Type: %02X Chan: %02X\n", type, chan);
516
517
    SDL_UnlockMutex(mrp->fifo_mutex);
518
    return FLUID_OK;
519
}
520
521
522
#else
523
void midi_load_sf2(uint8_t* filename)
524
{
525
    // no-op
526
}
527
528
void midi_init()
529
{
530
    fprintf(stderr, "No FluidSynth support.\n");
531
}
532
533
void midi_byte_out(uint8_t sel, uint8_t b)
534
{
535
    // no-op
536
}
537
538
void midi_synth_render(int16_t* buf, int len)
539
{
540
    // no synth, return zeroed buffer
541
    memset(buf, 0, len * 2 * sizeof(int16_t));
542
}
543
544
#endif
545
546
void midi_serial_init()
547
{
548
    uint8_t sel;
549
550
    for (sel=0; sel<2; sel++) {
551
        mregs[sel].ier_erbi = false;
552
        mregs[sel].ier_etbei = false;
553
        mregs[sel].ier_elsi = false;
554
        mregs[sel].ier_edssi = false;
555
556
        mregs[sel].iir = 0x01;
557
558
        mregs[sel].fcr_fifo_enable = false;
559
        mregs[sel].fcr_ififo_trigger_level_bytes = 1;
560
561
        mregs[sel].lcr_word_length_bits = 5;
562
        mregs[sel].lcr_stb = false;
563
        mregs[sel].lcr_pen = false;
564
        mregs[sel].lcr_eps = false;
565
        mregs[sel].lcr_stick = false;
566
        mregs[sel].lcr_break = false;
567
        mregs[sel].lcr_dlab = false;
568
569
        mregs[sel].mcr_dtr = false;
570
        mregs[sel].mcr_rts = false;
571
        mregs[sel].mcr_out1 = false;
572
        mregs[sel].mcr_out2 = false;
573
        mregs[sel].mcr_loop = false;
574
        mregs[sel].mcr_afe = false;
575
576
        mregs[sel].lsr_oe = false;
577
        mregs[sel].lsr_pe = false;
578
        mregs[sel].lsr_fe = false;
579
        mregs[sel].lsr_bi = false;
580
        mregs[sel].lsr_eif = false;
581
582
        mregs[sel].msr_dcts = false;
583
        mregs[sel].msr_ddsr = false;
584
        mregs[sel].msr_teri = false;
585
        mregs[sel].msr_ddcd = false;
586
587
        mregs[sel].msr_cts = false;
588
        mregs[sel].msr_dsr = false;
589
        mregs[sel].msr_ri = false;
590
        mregs[sel].msr_dcd = false;
591
592
        mregs[sel].obyte_bits_remain = 0;
593
        mregs[sel].rx_timeout = 0;
594
        mregs[sel].rx_timeout_enabled = false;
595
        mregs[sel].thre_intr = false;
596
        mregs[sel].thre_bits_remain = 0;
597
598
        mregs[sel].ibyte_bits_remain = 7;
599
600
        mregs[sel].ifsz = 0;
601
        mregs[sel].ififo[0] = 0;
602
        mregs[sel].ofsz = 0;
603
        mregs[sel].clock = 0;
604
        mregs[sel].clockdec = 0;
605
        mregs[sel].last_warning = 0;
606
607
        mregs[sel].mfsz = 0;
608
        mregs[sel].in_midi_last_command = 0;
609
    }
610
611
    if (!serial_midi_mutexes_initialized) {
612
        for (sel=0; sel<2; sel++) {
613
            mregs[sel].fifo_mutex = SDL_CreateMutex();
614
        }
615
        serial_midi_mutexes_initialized = true;
616
    }
617
}
618
619
void midi_serial_iir_check(uint8_t sel)
620
{
621
    uint8_t fifoen = (uint8_t)mregs[sel].fcr_fifo_enable << 6 | (uint8_t)mregs[sel].fcr_fifo_enable << 7;
622
    if (mregs[sel].ier_elsi && (mregs[sel].lsr_oe || mregs[sel].lsr_pe || mregs[sel].lsr_fe || mregs[sel].lsr_bi)) {
623
        mregs[sel].iir = (0x06 | fifoen); // Receiver line status interrupt
624
    } else if (mregs[sel].ier_erbi && !mregs[sel].fcr_fifo_enable && mregs[sel].ifsz > 0) {
625
        mregs[sel].iir = (0x04 | fifoen); // Received data available interrupt (16450 mode)
626
    } else if (mregs[sel].ier_erbi && mregs[sel].fcr_fifo_enable && mregs[sel].ifsz >= mregs[sel].fcr_ififo_trigger_level_bytes) {
627
        mregs[sel].iir = (0x04 | fifoen); // Received data available interrupt (16550 mode)
628
    } else if (mregs[sel].ier_erbi && mregs[sel].fcr_fifo_enable && mregs[sel].ifsz > 0 && mregs[sel].rx_timeout_enabled && mregs[sel].rx_timeout == 0) {
629
        mregs[sel].iir = (0x0c | fifoen); // Received data available interrupt (timeout, 16550 mode)
630
    } else if (mregs[sel].ier_etbei && mregs[sel].thre_intr) {
631
        mregs[sel].iir = (0x02 | fifoen); // Transmitter holding register empty interrupt
632
    } else if (mregs[sel].ier_edssi && ((!mregs[sel].mcr_afe && mregs[sel].msr_dcts) || mregs[sel].msr_ddcd || mregs[sel].msr_ddsr || mregs[sel].msr_teri)) {
633
        mregs[sel].iir = (0x00 | fifoen); // Modem status register interrupt
634
    } else {
635
        mregs[sel].iir = (0x01 | fifoen); // no interrupt waiting
636
    }
637
}
638
639
void midi_serial_step(int clocks)
640
{
641
    uint8_t sel, i;
642
    for (sel=0; sel<2; sel++) {
643
        mregs[sel].clock -= (int64_t)mregs[sel].clockdec * clocks;
644
        while (mregs[sel].clock < 0) {
645
            // process uart
646
            SDL_LockMutex(mregs[sel].fifo_mutex);
647
648
            if (mregs[sel].obyte_bits_remain > 0) {
649
                mregs[sel].obyte_bits_remain--;
650
            }
651
            if (mregs[sel].ofsz > 0) {
652
                if (mregs[sel].obyte_bits_remain == 0) {
653
                    midi_byte_out(sel, mregs[sel].ofifo[0]);
654
                    mregs[sel].ofsz--;
655
                    if (mregs[sel].ofsz > 0) {
656
                        for (i=0; i<mregs[sel].ofsz; i++) {
657
                            mregs[sel].ofifo[i] = mregs[sel].ofifo[i+1];
658
                        }
659
                    } else if (mregs[sel].thre_bits_remain == 0) {
660
                        mregs[sel].thre_intr = true;
661
                    }
662
                    mregs[sel].obyte_bits_remain = 2 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen;
663
                }
664
            } else {
665
                if (mregs[sel].thre_bits_remain > 0) {
666
                    mregs[sel].thre_bits_remain--;
667
                    if (mregs[sel].thre_bits_remain == 0) {
668
                        mregs[sel].thre_intr = true;
669
                    }
670
                }
671
            }
672
673
            if (mregs[sel].rx_timeout > 0) {
674
                mregs[sel].rx_timeout--;
675
            }
676
677
            if (mregs[sel].ibyte_bits_remain > 0 && mregs[sel].mfsz > 0) {
678
                mregs[sel].ibyte_bits_remain--;
679
            }
680
            if (mregs[sel].ibyte_bits_remain == 0 && mregs[sel].mfsz > 0) {
681
                if (mregs[sel].ifsz < (mregs[sel].fcr_fifo_enable ? 16 : 1)) {
682
                    mregs[sel].ififo[mregs[sel].ifsz++] = mregs[sel].midi_event_fifo[0];
683
                    mregs[sel].rx_timeout_enabled = true;
684
                    mregs[sel].rx_timeout = 4 * (2 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen);
685
                } else {
686
                    mregs[sel].lsr_oe = true; // inbound FIFO overflow
687
                    if (!mregs[sel].fcr_fifo_enable) {
688
                        // RBR is overwritten by RSR in this mode
689
                        // whenever overflow happens
690
                        mregs[sel].ififo[mregs[sel].ifsz-1] = mregs[sel].midi_event_fifo[0];
691
                    }
692
                }
693
                mregs[sel].mfsz--;
694
                if (mregs[sel].mfsz > 0) {
695
                    for (i=0; i<mregs[sel].mfsz; i++) {
696
                        mregs[sel].midi_event_fifo[i] = mregs[sel].midi_event_fifo[i+1];
697
                    }
698
                }
699
                mregs[sel].ibyte_bits_remain = 2 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen;
700
            }
701
702
            SDL_UnlockMutex(mregs[sel].fifo_mutex);
703
            mregs[sel].clock += 0x1000000LL;
704
            midi_serial_iir_check(sel);
705
        }
706
    }
707
}
708
709
uint8_t midi_serial_dequeue_ibyte(uint8_t sel)
710
{
711
    SDL_LockMutex(mregs[sel].fifo_mutex);
712
    uint8_t ret = mregs[sel].ififo[0];
713
    uint8_t i;
714
715
    if (mregs[sel].ifsz > 0) {
716
        mregs[sel].ifsz--;
717
        if (mregs[sel].ifsz == 0) {
718
            mregs[sel].rx_timeout_enabled = false;
719
        } else {
720
            for (i=0; i<mregs[sel].ifsz; i++) {
721
                mregs[sel].ififo[i] = mregs[sel].ififo[i+1];
722
            }
723
            mregs[sel].rx_timeout_enabled = true;
724
            mregs[sel].rx_timeout = 4 * (2 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen);
725
        }
726
        midi_serial_iir_check(sel);
727
    }
728
729
    SDL_UnlockMutex(mregs[sel].fifo_mutex);
730
    return ret;
731
}
732
733
void midi_serial_enqueue_obyte(uint8_t sel, uint8_t val)
734
{
735
    SDL_LockMutex(mregs[sel].fifo_mutex);
736
    if (mregs[sel].ofsz < (mregs[sel].fcr_fifo_enable ? 16 : 1)) {
737
        mregs[sel].ofifo[mregs[sel].ofsz] = val;
738
        mregs[sel].thre_intr = false;
739
        mregs[sel].ofsz++;
740
        if (mregs[sel].ofsz == 1) { // We were empty
741
            if (mregs[sel].fcr_fifo_enable) {
742
                // We delay a bit longer to reraise the THRE interrupt if we're coming from 0
743
                mregs[sel].thre_bits_remain = 1 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen;
744
            }
745
        } else {
746
            mregs[sel].thre_bits_remain = 0;
747
        }
748
    } else {
749
        fprintf(stderr, "Serial MIDI: Warning: UART %d TX Overflow\n", sel);
750
    }
751
    midi_serial_iir_check(sel);
752
    SDL_UnlockMutex(mregs[sel].fifo_mutex);
753
}
754
755
uint8_t midi_serial_read(uint8_t reg, bool debugOn)
756
{
757
    //printf("midi_serial_read %d\n", reg);
758
    uint8_t sel = (reg & 8) >> 3;
759
    switch (reg & 7) {
760
        case 0x0:
761
            if (mregs[sel].lcr_dlab) {
762
                return mregs[sel].dll;
763
            } else {
764
                if (debugOn) {
765
                    return mregs[sel].ififo[0];
766
                } else {
767
                    return midi_serial_dequeue_ibyte(sel);
768
                }
769
            }
770
            break;
771
        case 0x1:
772
            if (mregs[sel].lcr_dlab) {
773
                return mregs[sel].dlm;
774
            } else {
775
                return (((uint8_t)mregs[sel].ier_edssi << 3) |
776
                        ((uint8_t)mregs[sel].ier_elsi << 2) |
777
                        ((uint8_t)mregs[sel].ier_etbei << 1) |
778
                        ((uint8_t)mregs[sel].ier_erbi));
779
            }
780
            break;
781
        case 0x2: {
782
            uint8_t ret = mregs[sel].iir;
783
            if (!debugOn) {
784
                mregs[sel].thre_intr = false;
785
                midi_serial_iir_check(sel);
786
            }
787
            return ret;
788
            break;
789
        }
790
        case 0x3:
791
            return (((uint8_t)mregs[sel].lcr_dlab << 7) |
792
                    ((uint8_t)mregs[sel].lcr_break << 6) |
793
                    ((uint8_t)mregs[sel].lcr_stick << 5) |
794
                    ((uint8_t)mregs[sel].lcr_eps << 4) |
795
                    ((uint8_t)mregs[sel].lcr_pen << 3) |
796
                    ((uint8_t)mregs[sel].lcr_stb << 2) |
797
                    ((mregs[sel].lcr_word_length_bits - 5) & 0x3));
798
            break;
799
        case 0x4:
800
            return (((uint8_t)mregs[sel].mcr_afe << 5) |
801
                    ((uint8_t)mregs[sel].mcr_loop << 4) |
802
                    ((uint8_t)mregs[sel].mcr_out2 << 3) |
803
                    ((uint8_t)mregs[sel].mcr_out1 << 2) |
804
                    ((uint8_t)mregs[sel].mcr_rts << 1) |
805
                    ((uint8_t)mregs[sel].mcr_dtr));
806
            break;
807
        case 0x5: {
808
            uint8_t ret = (((uint8_t)mregs[sel].lsr_eif << 7) |
809
                    ((uint8_t)(mregs[sel].obyte_bits_remain == 0 && mregs[sel].ofsz == 0) << 6) |
810
                    ((uint8_t)(mregs[sel].ofsz == 0) << 5) |
811
                    ((uint8_t)mregs[sel].lsr_bi << 4) |
812
                    ((uint8_t)mregs[sel].lsr_fe << 3) |
813
                    ((uint8_t)mregs[sel].lsr_pe << 2) |
814
                    ((uint8_t)mregs[sel].lsr_oe << 1) |
815
                    ((uint8_t)(mregs[sel].ifsz > 0)));
816
            if (!debugOn) {
817
                mregs[sel].lsr_oe = false;
818
                mregs[sel].lsr_pe = false;
819
                mregs[sel].lsr_fe = false;
820
                mregs[sel].lsr_bi = false;
821
            }
822
            return ret;
823
            break;
824
        }
825
        case 0x6:
826
            return (((uint8_t)mregs[sel].msr_dcd << 7) |
827
                    ((uint8_t)mregs[sel].msr_ri << 6) |
828
                    ((uint8_t)mregs[sel].msr_dsr << 5) |
829
                    ((uint8_t)mregs[sel].msr_cts << 4) |
830
                    ((uint8_t)mregs[sel].msr_ddcd << 3) |
831
                    ((uint8_t)mregs[sel].msr_teri << 2) |
832
                    ((uint8_t)mregs[sel].msr_ddsr << 1) |
833
                    ((uint8_t)mregs[sel].msr_dcts));
834
            break;
835
        case 0x7:
836
            return mregs[sel].scratch;
837
            break;
838
    }
839
    return 0x00;
840
}
841
842
void midi_serial_calculate_clk(uint8_t sel)
843
{
844
    double uart_clks_per_cpu = (MIDI_UART_OSC_RATE_MHZ / MIDI_UART_PRIMARY_DIVIDER) / MHZ;
845
    if (mregs[sel].dl > 0) {
846
        uart_clks_per_cpu /= mregs[sel].dl;
847
        mregs[sel].clockdec = uart_clks_per_cpu * 0x1000000L; // convert to 8.24 fixed point
848
    } else {
849
        mregs[sel].clockdec = 0;
850
    }
851
}
852
853
void midi_serial_write(uint8_t reg, uint8_t val)
854
{
855
    time_t now = time(NULL);
856
857
    //printf("midi_serial_write %d %d\n", reg, val);
858
    uint8_t sel = (reg & 8) >> 3;
859
    switch (reg & 7) {
860
        case 0x0:
861
            if (mregs[sel].lcr_dlab) {
862
                mregs[sel].dll = val;
863
                midi_serial_calculate_clk(sel);
864
            } else {
865
                if (mregs[sel].lcr_word_length_bits != 8 || mregs[sel].lcr_stb || mregs[sel].lcr_pen) {
866
                    if (mregs[sel].last_warning + 60 < now) {
867
                        unsigned char par = 'N';
868
                        if (mregs[sel].lcr_pen) {
869
                            switch ((uint8_t)(mregs[sel].lcr_eps << 1) | (uint8_t)mregs[sel].lcr_stick) {
870
                                case 0:
871
                                    par = 'O';
872
                                    break;
873
                                case 1:
874
                                    par = 'M';
875
                                    break;
876
                                case 2:
877
                                    par = 'E';
878
                                    break;
879
                                case 3:
880
                                    par = 'S';
881
                                    break;
882
                            }
883
                        }
884
                        fprintf(stderr, "Serial MIDI: Warning: improper LCR %d%c%d for UART %d, must be set to 8N1.\n", mregs[sel].lcr_word_length_bits, par, 1+(uint8_t)mregs[sel].lcr_stb, sel);
885
                        mregs[sel].last_warning = now;
886
                    }
887
                } else if (mregs[sel].lcr_break && mregs[sel].last_warning + 60 < now) {
888
                    fprintf(stderr, "Serial MIDI: Warning: break improperly set for UART %d.\n", sel);
889
                    mregs[sel].last_warning = now;
890
                } else if (mregs[sel].dl != 32 && mregs[sel].last_warning + 60 < now) {
891
                    fprintf(stderr, "Serial MIDI: Warning: improper divisor %d for UART %d, must be set to 32 for standard MIDI bitrate.\n", mregs[sel].dl, sel);
892
                    mregs[sel].last_warning = now;
893
                } else {
894
                    midi_serial_enqueue_obyte(sel, val);
895
                }
896
            }
897
            break;
898
        case 0x1:
899
            if (mregs[sel].lcr_dlab) {
900
                mregs[sel].dlm = val;
901
                midi_serial_calculate_clk(sel);
902
            } else {
903
                mregs[sel].ier_erbi = !!(val & 1);
904
                mregs[sel].ier_etbei = !!(val & 2);
905
                mregs[sel].ier_elsi = !!(val & 4);
906
                mregs[sel].ier_edssi = !!(val & 8);
907
            }
908
            break;
909
        case 0x2:
910
            if (val & 1) {
911
                mregs[sel].fcr_fifo_enable = true;
912
                switch ((val & 0xc0) >> 6) {
913
                    case 0:
914
                        mregs[sel].fcr_ififo_trigger_level_bytes = 1;
915
                        break;
916
                    case 1:
917
                        mregs[sel].fcr_ififo_trigger_level_bytes = 4;
918
                        break;
919
                    case 2:
920
                        mregs[sel].fcr_ififo_trigger_level_bytes = 8;
921
                        break;
922
                    case 3:
923
                        mregs[sel].fcr_ififo_trigger_level_bytes = 14;
924
                        break;
925
                }
926
            } else {
927
                mregs[sel].fcr_fifo_enable = false;
928
                mregs[sel].fcr_ififo_trigger_level_bytes = 1;
929
            }
930
            if (val & 2) {
931
                mregs[sel].ifsz = 0;
932
            }
933
            if (val & 4) {
934
                mregs[sel].ofsz = 0;
935
            }
936
            if (mregs[sel].thre_bits_remain == 0) { 
937
                mregs[sel].thre_intr = true;
938
            }
939
            midi_serial_iir_check(sel);
940
            break;
941
        case 0x3:
942
            mregs[sel].lcr_word_length_bits = (val & 0x03)+5;
943
            mregs[sel].lcr_stb = !!(val & 0x04);
944
            mregs[sel].lcr_pen = !!(val & 0x08);
945
            mregs[sel].lcr_eps = !!(val & 0x10);
946
            mregs[sel].lcr_stick = !!(val & 0x20);
947
            mregs[sel].lcr_break = !!(val & 0x40);
948
            mregs[sel].lcr_dlab = !!(val & 0x80);
949
            if (mregs[sel].mfsz == 0) {
950
                mregs[sel].ibyte_bits_remain = 2 + mregs[sel].lcr_word_length_bits + mregs[sel].lcr_stb + mregs[sel].lcr_pen;
951
            }
952
            break;
953
        case 0x4:
954
            mregs[sel].mcr_dtr = !!(val & 0x01);
955
            mregs[sel].mcr_rts = !!(val & 0x02);
956
            mregs[sel].mcr_out1 = !!(val & 0x04);
957
            mregs[sel].mcr_out2 = !!(val & 0x08);
958
            mregs[sel].mcr_loop = !!(val & 0x10);
959
            mregs[sel].mcr_afe = !!(val & 0x20);
960
961
            if (mregs[sel].mcr_loop) {
962
                mregs[sel].msr_dcts |= mregs[sel].msr_cts ^ mregs[sel].mcr_dtr;
963
                mregs[sel].msr_cts = mregs[sel].mcr_dtr;
964
965
                mregs[sel].msr_ddsr |= mregs[sel].msr_dsr ^ mregs[sel].mcr_rts;
966
                mregs[sel].msr_dsr = mregs[sel].mcr_rts;
967
968
                if (mregs[sel].msr_ri) {
969
                    mregs[sel].msr_teri |= mregs[sel].msr_ri ^ mregs[sel].mcr_out1;
970
                }
971
                mregs[sel].msr_ri = mregs[sel].mcr_out1;
972
973
                mregs[sel].msr_ddcd |= mregs[sel].msr_dcd ^ mregs[sel].mcr_out2;
974
                mregs[sel].msr_dcd = mregs[sel].mcr_out2;
975
976
            } else {
977
                // DTR tied to RI on opposite UART, wired this way on the official X16 MIDI card
978
                if (mregs[sel ^ 1].msr_ri && !mregs[sel].mcr_dtr) {
979
                    mregs[sel ^ 1].msr_teri = true;
980
                }
981
                mregs[sel ^ 1].msr_ri = mregs[sel].mcr_dtr;
982
            }
983
984
            break;
985
        case 0x7:
986
            mregs[sel].scratch = val;
987
            break;
988
    }
989
}
990
991
bool midi_serial_irq(void)
992
{
993
    bool uart0int = (mregs[0].iir & 1) == 0 && mregs[0].mcr_out2;
994
    bool uart1int = (mregs[1].iir & 1) == 0 && mregs[1].mcr_out2;
995
    return (uart0int | uart1int);
996
}