diff options
Diffstat (limited to 'backends/midi')
-rw-r--r-- | backends/midi/adlib.cpp | 1366 |
1 files changed, 1366 insertions, 0 deletions
diff --git a/backends/midi/adlib.cpp b/backends/midi/adlib.cpp new file mode 100644 index 0000000000..a831c9f062 --- /dev/null +++ b/backends/midi/adlib.cpp @@ -0,0 +1,1366 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + */ + +/* + * Timidity support by Lionel Ulmer <lionel.ulmer@free.fr> + * QuickTime support by Florent Boudet <flobo@ifrance.com> + * Raw output support by Michael Pearce + * MorphOS support by Ruediger Hanke + * Alsa support by Nicolas Noble <nicolas@nobis-crew.org> copied from + * both the QuickTime support and (vkeybd http://www.alsa-project.org/~iwai/alsa.html) + */ + +#include "stdafx.h" +#include "mididrv.h" +#include "fmopl.h" +#include "mixer.h" +#include "scumm.h" +#include "imuse.h" +#include "common/engine.h" // for warning/error/debug +#include "common/util.h" + +class MidiDriver_ADLIB; +struct MidiChannelAdl; + +struct InstrumentExtra { + byte a, b, c, d, e, f, g, h; +}; + +struct Instrument { + byte flags_1; + byte oplvl_1; + byte atdec_1; + byte sustrel_1; + byte waveform_1; + byte flags_2; + byte oplvl_2; + byte atdec_2; + byte sustrel_2; + byte waveform_2; + byte feedback; + byte flags_a; + InstrumentExtra extra_a; + byte flags_b; + InstrumentExtra extra_b; + byte duration; +}; + +struct AdlibPart { + byte _chan; + AdlibPart *_prev, *_next; + MidiDriver_ADLIB *_drv; + MidiChannelAdl *_mc; + int16 _pitchbend; + byte _pitchbend_factor; + int8 _transpose_eff; + byte _vol_eff; + int8 _detune_eff; + byte _modwheel; + bool _pedal; + byte _program; + byte _pri_eff; + Instrument _part_instr; +}; + +struct Struct10 { + byte active; + int16 cur_val; + int16 count; + uint16 param; + int16 start_value; + byte loop; + byte table_a[4]; + byte table_b[4]; + int8 unk3; + int8 modwheel; + int8 modwheel_last; + uint16 speed_lo_max; + uint16 num_steps; + int16 speed_hi; + int8 direction; + uint16 speed_lo; + uint16 speed_lo_counter; +}; + +struct Struct11 { + int16 modify_val; + byte param, flag0x40, flag0x10; + Struct10 *s10; +}; + +struct MidiChannelAdl { + AdlibPart *_part; + MidiChannelAdl *_next, *_prev; + byte _waitforpedal; + byte _note; + byte _channel; + byte _twochan; + byte _vol_1, _vol_2; + int16 _duration; + + Struct10 _s10a; + Struct11 _s11a; + Struct10 _s10b; + Struct11 _s11b; + + MidiChannelAdl() : _part (0), _next(0), _prev(0) {} +}; + +struct AdlibSetParams { + byte a, b, c, d; +}; + +static const byte channel_mappings[9] = { + 0, 1, 2, 8, + 9, 10, 16, 17, + 18 +}; + +static const byte channel_mappings_2[9] = { + 3, 4, 5, 11, + 12, 13, 19, 20, + 21 +}; + +static const AdlibSetParams adlib_setparam_table[] = { + {0x40, 0, 63, 63}, // level + {0xE0, 2, 0, 0}, // unused + {0x40, 6, 192, 0}, // level key scaling + {0x20, 0, 15, 0}, // modulator frequency multiple + {0x60, 4, 240, 15}, // attack rate + {0x60, 0, 15, 15}, // decay rate + {0x80, 4, 240, 15}, // sustain level + {0x80, 0, 15, 15}, // release rate + {0xE0, 0, 3, 0}, // waveform select + {0x20, 7, 128, 0}, // amp mod + {0x20, 6, 64, 0}, // vib + {0x20, 5, 32, 0}, // eg typ + {0x20, 4, 16, 0}, // ksr + {0xC0, 0, 1, 0}, // decay alg + {0xC0, 1, 14, 0} // feedback +}; + +const byte param_table_1[16] = { + 29, 28, 27, 0, + 3, 4, 7, 8, + 13, 16, 17, 20, + 21, 30, 31, 0 +}; + +const uint16 param_table_2[16] = { + 0x2FF, 0x1F, 0x7, 0x3F, + 0x0F, 0x0F, 0x0F, 0x3, + 0x3F, 0x0F, 0x0F, 0x0F, + 0x3, 0x3E, 0x1F, 0 +}; + +static const uint16 num_steps_table[] = { + 1, 2, 4, 5, + 6, 7, 8, 9, + 10, 12, 14, 16, + 18, 21, 24, 30, + 36, 50, 64, 82, + 100, 136, 160, 192, + 240, 276, 340, 460, + 600, 860, 1200, 1600 +}; + +static const byte octave_numbers[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static const byte note_numbers[] = { + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10 +}; + +static const byte note_to_f_num[] = { + 90, 91, 92, 92, 93, 94, 94, 95, + 96, 96, 97, 98, 98, 99, 100, 101, + 101, 102, 103, 104, 104, 105, 106, 107, + 107, 108, 109, 110, 111, 111, 112, 113, + 114, 115, 115, 116, 117, 118, 119, 120, + 121, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, + 143, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 157, 158, 159, 160, + 161, 162, 163, 165, 166, 167, 168, 169, + 171, 172, 173, 174, 176, 177, 178, 180, + 181, 182, 184, 185, 186, 188, 189, 190, + 192, 193, 194, 196, 197, 199, 200, 202, + 203, 205, 206, 208, 209, 211, 212, 214, + 215, 217, 218, 220, 222, 223, 225, 226, + 228, 230, 231, 233, 235, 236, 238, 240, + 242, 243, 245, 247, 249, 251, 252, 254, +}; + +static byte map_gm_to_fm [128][30] = { +// DERIVED FROM DAY OF THE TENTACLE + // 00 +{ 0x2F, 0x0B, 0x08, 0x78, 0x16, 0x24, 0x22, 0x0B, 0x9A, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x2F, 0x0B, 0x08, 0x78, 0x16, 0x24, 0x22, 0x0B, 0x9A, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0x84, 0x40, 0x3B, 0x5A, 0x63, 0x81, 0x00, 0x3B, 0x5A, 0x7F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x2F, 0x0B, 0x08, 0x78, 0x16, 0x24, 0x22, 0x0B, 0x9A, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x84, 0x40, 0x3B, 0x5A, 0x63, 0x81, 0x00, 0x3B, 0x5A, 0x7F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x2F, 0x0B, 0x08, 0x78, 0x16, 0x24, 0x22, 0x0B, 0x9A, 0x34, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0x85, 0x80, 0x05, 0xEA, 0x3D, 0x84, 0x18, 0x3C, 0xAA, 0x7C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xE2, 0x00, 0x6C, 0x77, 0x7D, 0xE4, 0x40, 0x7D, 0xA7, 0x66, 0x07, 0xA1, 0x00, 0x02, 0x1E, 0x01, 0x20, 0x01, 0x01, 0x1F, 0xAC, 0x00, 0x04, 0x24, 0x02, 0x21, 0x02, 0x02, 0x21, 0x00 }, + // 10 +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xC9, 0x40, 0x3A, 0x78, 0x5E, 0xC2, 0x00, 0x4D, 0x9A, 0x7C, 0x00, 0xA1, 0xA0, 0x08, 0x1F, 0x05, 0x1E, 0x02, 0x05, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x28, 0x1D, 0x19, 0x68, 0x02, 0x22, 0x35, 0x09, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0x28, 0x1D, 0x19, 0x68, 0x02, 0x22, 0x35, 0x09, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xC6, 0x40, 0x3B, 0x78, 0x5E, 0xC2, 0x00, 0x4D, 0x9A, 0x7C, 0x00, 0xA1, 0xA0, 0x08, 0x1F, 0x05, 0x1E, 0x02, 0x05, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xE2, 0x00, 0x6C, 0x77, 0x7D, 0xE4, 0x40, 0x7D, 0xA7, 0x66, 0x07, 0xA1, 0x00, 0x02, 0x1E, 0x01, 0x20, 0x01, 0x01, 0x1F, 0xAC, 0x00, 0x04, 0x24, 0x02, 0x21, 0x02, 0x02, 0x21, 0x00 }, +{ 0xE2, 0x28, 0x38, 0xE8, 0x02, 0xE6, 0x33, 0x0B, 0xF9, 0x00, 0x08, 0xA1, 0x00, 0x02, 0x1E, 0x02, 0x20, 0x00, 0x02, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0xE2, 0x28, 0x38, 0xE8, 0x02, 0xE6, 0x33, 0x0B, 0xF9, 0x00, 0x08, 0xA1, 0x00, 0x02, 0x1E, 0x02, 0x20, 0x00, 0x02, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xE2, 0x00, 0x6C, 0x77, 0x7D, 0xE4, 0x40, 0x7D, 0xA7, 0x66, 0x07, 0xA1, 0x00, 0x02, 0x1E, 0x01, 0x20, 0x01, 0x01, 0x1F, 0xAC, 0x00, 0x04, 0x24, 0x02, 0x21, 0x02, 0x02, 0x21, 0x00 }, + // 20 +{ 0x85, 0x80, 0x05, 0xEA, 0x3D, 0x84, 0x18, 0x3C, 0xAA, 0x7C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0x85, 0x80, 0x05, 0xEA, 0x3D, 0x84, 0x18, 0x3C, 0xAA, 0x7C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0x85, 0x80, 0x05, 0xEA, 0x3D, 0x84, 0x18, 0x3C, 0xAA, 0x7C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xC6, 0x00, 0x2E, 0xC7, 0x59, 0xC2, 0x06, 0x0E, 0xA7, 0x7D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0xC6, 0x00, 0x2E, 0xC7, 0x59, 0xC2, 0x06, 0x0E, 0xA7, 0x7D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0xC6, 0x00, 0x2E, 0xC7, 0x59, 0xC2, 0x06, 0x0E, 0xA7, 0x7D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xC6, 0x00, 0x2E, 0xC7, 0x59, 0xC2, 0x06, 0x0E, 0xA7, 0x7D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x84, 0x40, 0x3B, 0x5A, 0x63, 0x81, 0x00, 0x3B, 0x5A, 0x7F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + // 30 +{ 0xC6, 0x00, 0x2E, 0xC7, 0x59, 0xC2, 0x06, 0x0E, 0xA7, 0x7D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x31, 0x0C, 0x2D, 0xD7, 0x40, 0x62, 0x18, 0x2E, 0xB8, 0x7C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x01, 0x1C, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00 }, +{ 0x22, 0x19, 0x79, 0x67, 0x00, 0x22, 0x3F, 0x2A, 0xC6, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x31, 0x0C, 0x2D, 0xD7, 0x40, 0x62, 0x18, 0x2E, 0xB8, 0x7C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x01, 0x1C, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00 }, +{ 0x31, 0x0C, 0x2D, 0xD7, 0x40, 0x62, 0x18, 0x2E, 0xB8, 0x7C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x01, 0x1C, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x31, 0x0C, 0x2D, 0xD7, 0x40, 0x62, 0x18, 0x2E, 0xB8, 0x7C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x01, 0x1C, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00 }, +{ 0x31, 0x0C, 0x2D, 0xD7, 0x40, 0x62, 0x18, 0x2E, 0xB8, 0x7C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x01, 0x1C, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00 }, // Extrapolated + // 40 +{ 0xE2, 0x15, 0x7B, 0xB5, 0x02, 0xE1, 0x33, 0xAF, 0xF4, 0x36, 0x08, 0xA1, 0x00, 0x04, 0x1E, 0x04, 0x1F, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xC6, 0x00, 0x2E, 0xC7, 0x59, 0xC2, 0x06, 0x0E, 0xA7, 0x7D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xF4, 0x40, 0x9F, 0xFA, 0x61, 0xE2, 0x13, 0x7F, 0xFA, 0x7D, 0x02, 0x21, 0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x35, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x02, 0x00, 0x67, 0xAA, 0x65, 0x02, 0x64, 0x28, 0xF9, 0x7C, 0x08, 0x81, 0x00, 0x04, 0x1D, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x02, 0x40, 0x04, 0x9A, 0x55, 0xC2, 0x4B, 0x2B, 0xCB, 0x7C, 0x06, 0x41, 0x00, 0x00, 0x20, 0x06, 0x1C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x02, 0x0C, 0x03, 0x6A, 0x7D, 0x02, 0x00, 0x23, 0xEA, 0x7C, 0x02, 0x81, 0x00, 0x02, 0x20, 0x01, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xF4, 0x40, 0x9F, 0xFA, 0x61, 0xE2, 0x13, 0x7F, 0xFA, 0x7D, 0x02, 0x21, 0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x35, 0x00 }, +{ 0xF4, 0x40, 0x9F, 0xFA, 0x61, 0xE2, 0x13, 0x7F, 0xFA, 0x7D, 0x02, 0x21, 0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x35, 0x00 }, + // 50 +{ 0xF4, 0x40, 0x9F, 0xFA, 0x61, 0xE2, 0x13, 0x7F, 0xFA, 0x7D, 0x02, 0x21, 0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x35, 0x00 }, +{ 0x02, 0x00, 0x67, 0xAA, 0x65, 0x02, 0x64, 0x28, 0xF9, 0x7C, 0x08, 0x81, 0x00, 0x04, 0x1D, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xE1, 0x00, 0xCE, 0xD9, 0x4E, 0xE2, 0x00, 0x8F, 0x99, 0x65, 0x0E, 0x01, 0x00, 0x01, 0x1F, 0x00, 0x1E, 0x01, 0x01, 0x20, 0x01, 0x00, 0x00, 0x1F, 0x06, 0x1E, 0x00, 0x06, 0x1F, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xE2, 0x00, 0xCE, 0xD9, 0x4C, 0xE2, 0x00, 0x8F, 0x99, 0x64, 0x0E, 0x81, 0x10, 0x00, 0x1E, 0x05, 0x1F, 0x12, 0x00, 0x1F, 0x01, 0x00, 0x00, 0x1F, 0x06, 0x1E, 0x00, 0x06, 0x1F, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xB2, 0x25, 0xAD, 0xE9, 0x00, 0x62, 0x00, 0x8F, 0xC8, 0x7C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xF2, 0x00, 0xAF, 0xFA, 0x5C, 0xF2, 0x56, 0x9F, 0xEA, 0x7C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xF2, 0x00, 0xAF, 0xFA, 0x5C, 0xF2, 0x56, 0x9F, 0xEA, 0x7C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xB2, 0x25, 0xAD, 0xE9, 0x00, 0x62, 0x00, 0x8F, 0xC8, 0x7C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + // 60 +{ 0xE2, 0x02, 0x9F, 0xB8, 0x48, 0x22, 0x89, 0x9F, 0xE8, 0x7C, 0x00, 0x81, 0x00, 0x01, 0x1E, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xB2, 0x25, 0xAD, 0xE9, 0x00, 0x62, 0x00, 0x8F, 0xC8, 0x7C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0xE4, 0x28, 0x7E, 0xF8, 0x01, 0xE2, 0x23, 0x8E, 0xE8, 0x7D, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0xE4, 0x28, 0x7E, 0xF8, 0x01, 0xE2, 0x23, 0x8E, 0xE8, 0x7D, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xE4, 0x28, 0x7E, 0xF8, 0x01, 0xE2, 0x23, 0x8E, 0xE8, 0x7D, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x31, 0x0C, 0x2D, 0xD7, 0x40, 0x62, 0x18, 0x2E, 0xB8, 0x7C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x01, 0x1C, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00 }, +{ 0x22, 0x10, 0x7E, 0xD8, 0x35, 0x2A, 0x2E, 0x8E, 0xD8, 0x7C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xE4, 0x28, 0x7E, 0xF8, 0x01, 0xE2, 0x23, 0x8E, 0xE8, 0x7D, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + // 70 +{ 0x22, 0x10, 0x7E, 0xD8, 0x35, 0x2A, 0x2E, 0x8E, 0xD8, 0x7C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xE4, 0x08, 0x7E, 0x99, 0x28, 0xE6, 0x16, 0x80, 0xF8, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xE4, 0x23, 0x8F, 0xF9, 0x7C, 0xE2, 0x18, 0x9F, 0x88, 0x7C, 0x01, 0x01, 0x04, 0x00, 0x1E, 0x00, 0x1F, 0x06, 0x05, 0x1F, 0x03, 0x29, 0x01, 0x1F, 0x02, 0x21, 0x01, 0x02, 0x1F, 0x00 }, +{ 0xE4, 0x23, 0x8F, 0xF9, 0x7C, 0xE2, 0x18, 0x9F, 0x88, 0x7C, 0x01, 0x01, 0x04, 0x00, 0x1E, 0x00, 0x1F, 0x06, 0x05, 0x1F, 0x03, 0x29, 0x01, 0x1F, 0x02, 0x21, 0x01, 0x02, 0x1F, 0x00 }, +{ 0xE4, 0x23, 0x8F, 0xF9, 0x7C, 0xE2, 0x18, 0x9F, 0x88, 0x7C, 0x01, 0x01, 0x04, 0x00, 0x1E, 0x00, 0x1F, 0x06, 0x05, 0x1F, 0x03, 0x29, 0x01, 0x1F, 0x02, 0x21, 0x01, 0x02, 0x1F, 0x00 }, +{ 0x2A, 0x1E, 0x98, 0xA9, 0x00, 0x62, 0x00, 0x9F, 0xB9, 0x7C, 0x00, 0x01, 0x00, 0x01, 0x1E, 0x00, 0x1F, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x2A, 0x1E, 0x98, 0xA9, 0x00, 0x62, 0x00, 0x9F, 0xB9, 0x7C, 0x00, 0x01, 0x00, 0x01, 0x1E, 0x00, 0x1F, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x62, 0xA8, 0x9D, 0x84, 0x44, 0x62, 0x23, 0x7F, 0xD5, 0x4C, 0x03, 0xA1, 0x00, 0x01, 0x1E, 0x02, 0x21, 0x01, 0x01, 0x20, 0xA8, 0x00, 0x01, 0x24, 0x06, 0x20, 0x04, 0x03, 0x24, 0x00 }, +{ 0xE4, 0x28, 0x7E, 0xF8, 0x01, 0xE2, 0x23, 0x8E, 0xE8, 0x7D, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + // 80 +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xE4, 0x08, 0x7E, 0x99, 0x28, 0xE6, 0x16, 0x80, 0xF8, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xE4, 0x28, 0x7E, 0xF8, 0x01, 0xE2, 0x23, 0x8E, 0xE8, 0x7D, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x22, 0x10, 0x7E, 0xD8, 0x35, 0x2A, 0x2E, 0x8E, 0xD8, 0x7C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xE4, 0x07, 0x05, 0xAA, 0x7C, 0xE2, 0x50, 0xBE, 0xC8, 0x7D, 0x07, 0x01, 0x00, 0x03, 0x1E, 0x01, 0x1E, 0x00, 0x00, 0x1E, 0xA8, 0x00, 0x01, 0x20, 0x06, 0x23, 0x04, 0x03, 0x20, 0x00 }, +{ 0x85, 0x80, 0x05, 0xEA, 0x3D, 0x84, 0x18, 0x3C, 0xAA, 0x7C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xB2, 0x25, 0xAD, 0xE9, 0x00, 0x62, 0x00, 0x8F, 0xC8, 0x7C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + // 90 +{ 0xF2, 0x00, 0xAF, 0xFA, 0x5C, 0xF2, 0x56, 0x9F, 0xEA, 0x7C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xE2, 0x02, 0x9F, 0xB8, 0x48, 0x22, 0x89, 0x9F, 0xE8, 0x7C, 0x00, 0x81, 0x00, 0x01, 0x1E, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xB2, 0x25, 0xAD, 0xE9, 0x00, 0x62, 0x00, 0x8F, 0xC8, 0x7C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xE2, 0x00, 0xCE, 0xD9, 0x4C, 0xE2, 0x00, 0x8F, 0x99, 0x64, 0x0E, 0x81, 0x10, 0x00, 0x1E, 0x05, 0x1F, 0x12, 0x00, 0x1F, 0x01, 0x00, 0x00, 0x1F, 0x06, 0x1E, 0x00, 0x06, 0x1F, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xC9, 0x40, 0x3A, 0x38, 0x5E, 0xC2, 0x00, 0x4C, 0xAA, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xC9, 0x40, 0x3A, 0x78, 0x5E, 0xC2, 0x00, 0x4D, 0x9A, 0x7C, 0x00, 0xA1, 0xA0, 0x08, 0x1F, 0x05, 0x1E, 0x02, 0x05, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown + // 100 +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xC9, 0x40, 0x3A, 0x38, 0x5E, 0xC2, 0x00, 0x4C, 0xAA, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0xC9, 0x40, 0x3A, 0x78, 0x5E, 0xC2, 0x00, 0x4D, 0x9A, 0x7C, 0x00, 0xA1, 0xA0, 0x08, 0x1F, 0x05, 0x1E, 0x02, 0x05, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Extrapolated +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xC6, 0x00, 0x2E, 0xC7, 0x59, 0xC2, 0x06, 0x0E, 0xA7, 0x7D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown + // 110 +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x02, 0x0C, 0x03, 0x6A, 0x7D, 0x02, 0x00, 0x23, 0xEA, 0x7C, 0x02, 0x81, 0x00, 0x02, 0x20, 0x01, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xCF, 0x3B, 0x2A, 0xFE, 0x7E, 0xC0, 0xC0, 0x0C, 0xEB, 0x63, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 }, // Extrapolated +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x02, 0x0C, 0x03, 0x6A, 0x7D, 0x02, 0x00, 0x23, 0xEA, 0x7C, 0x02, 0x81, 0x00, 0x02, 0x20, 0x01, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x0F, 0x10, 0x10, 0x09, 0x49, 0x02, 0x12, 0x07, 0x9A, 0x7C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0xCF, 0x3B, 0x2A, 0xFE, 0x7E, 0xC0, 0xC0, 0x0C, 0xEB, 0x63, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown + // 120 +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0xCF, 0x40, 0x0A, 0x30, 0x5C, 0xCF, 0x00, 0x0D, 0x80, 0x7C, 0x00, 0xA0, 0x00, 0x0F, 0x1E, 0x0F, 0x20, 0x00, 0x0B, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Unknown +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // Unknown +}; + +static byte lookup_table[64][32]; +const byte volume_table[] = { + 0, 4, 7, 11, + 13, 16, 18, 20, + 22, 24, 26, 27, + 29, 30, 31, 33, + 34, 35, 36, 37, + 38, 39, 40, 41, + 42, 43, 44, 44, + 45, 46, 47, 47, + 48, 49, 49, 50, + 51, 51, 52, 53, + 53, 54, 54, 55, + 55, 56, 56, 57, + 57, 58, 58, 59, + 59, 60, 60, 60, + 61, 61, 62, 62, + 62, 63, 63, 63 +}; + +static int lookup_volume(int a, int b) +{ + if (b == 0) + return 0; + + if (b == 31) + return a; + + if (a < -63 || a > 63) { + return b * (a + 1) >> 5; + } + + if (b < 0) { + if (a < 0) { + return lookup_table[-a][-b]; + } else { + return -lookup_table[a][-b]; + } + } else { + if (a < 0) { + return -lookup_table[-a][b]; + } else { + return lookup_table[a][b]; + } + } +} + +static void create_lookup_table() +{ + int i, j; + int sum; + + for (i = 0; i < 64; i++) { + sum = i; + for (j = 0; j < 32; j++) { + lookup_table[i][j] = sum >> 5; + sum += i; + } + } + for (i = 0; i < 64; i++) + lookup_table[i][0] = 0; +} + +typedef void TimerCallback (void *); + + + +//////////////////////////////////////// +// +// Adlib MIDI driver +// +//////////////////////////////////////// + +class MidiDriver_ADLIB : public MidiDriver { +public: + MidiDriver_ADLIB(); + + int open(int mode); + void close(); + void send(uint32 b); + void pause(bool p) { } + void set_stream_callback(void *param, StreamCallback *sc) { } // No streaming support. Use MidiStreamer wrapper + void setPitchBendRange (byte channel, uint range); + void sysEx_customInstrument (byte channel, uint32 type, byte *instr); + + void setTimerCallback (void *timer_param, void (*timer_proc) (void *)); + uint32 getBaseTempo() { +#ifdef _WIN32_WCE + return 0x1D9000 * 2; // Sampled down to 11 kHz +#else //_WIN32_WCE + return 0x1D9000; +#endif //_WIN32_WCE + } + +private: + int _mode; + + FM_OPL *_opl; + byte *_adlib_reg_cache; + SoundMixer *_mixer; + + TimerCallback *_timer_proc; + void *_timer_param; + + int _adlib_timer_counter; + + uint16 channel_table_2[9]; + int _midichan_index; + int _next_tick; + uint16 curnote_table[9]; + MidiChannelAdl _midi_channels[9]; + AdlibPart _parts[16]; + + void generate_samples(int16 *buf, int len); + void on_timer(); + void part_set_instrument (AdlibPart *part, Instrument * instr); + void part_key_on (byte chan, byte note, byte velocity); + void part_key_off (byte chan, byte note); + + void adlib_key_off(int chan); + void adlib_note_on(int chan, byte note, int mod); + void adlib_note_on_ex(int chan, byte note, int mod); + int adlib_read_param(int chan, byte data); + void adlib_setup_channel(int chan, Instrument * instr, byte vol_1, byte vol_2); + byte adlib_read(byte port) { + return _adlib_reg_cache[port]; + } + void adlib_set_param(int channel, byte param, int value); + void adlib_key_onoff(int channel); + void adlib_write(byte port, byte value); + void adlib_playnote(int channel, int note); + + MidiChannelAdl *allocate_midichan(byte pri); + + void reset_tick(); + void mc_off(MidiChannelAdl * mc); + + static void link_mc (AdlibPart *part, MidiChannelAdl *mc); + static void mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11 * s11); + static void mc_init_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11 * s11, byte flags, + InstrumentExtra * ie); + + static void struct10_init(Struct10 * s10, InstrumentExtra * ie); + static byte struct10_ontimer(Struct10 * s10, Struct11 * s11); + static void struct10_setup(Struct10 * s10); + static int random_nr(int a); + void mc_key_on (MidiChannelAdl * mc, byte note, byte velocity); + + static void premix_proc(void *param, int16 *buf, uint len); +}; + + + +// MidiDriver method implementations + +MidiDriver_ADLIB::MidiDriver_ADLIB() +{ + uint i; + for (i = 0; i < ARRAYSIZE(_parts); ++i) { + _parts [i]._chan = i; + _parts [i]._prev = (i ? &_parts[i-1] : 0); + _parts [i]._next = ((i < ARRAYSIZE(_parts) - 1) ? &_parts[i+1] : 0); + _parts [i]._drv = this; + } +} + +int MidiDriver_ADLIB::open (int mode) +{ + if (_mode != 0) + return MERR_ALREADY_OPEN; + if (mode != MO_SIMPLE) + return MERR_STREAMING_NOT_AVAILABLE; + _mode = mode; + + int i; + MidiChannelAdl *mc; + + for (i = 0, mc = _midi_channels; i != ARRAYSIZE(_midi_channels); i++, mc++) { + mc->_channel = i; + mc->_s11a.s10 = &mc->_s10b; + mc->_s11b.s10 = &mc->_s10a; + } + + _adlib_reg_cache = (byte *)calloc(256, 1); + + _opl = OPLCreate(OPL_TYPE_YM3812, 3579545, g_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0)); + + adlib_write(1, 0x20); + adlib_write(8, 0x40); + adlib_write(0xBD, 0x00); + create_lookup_table(); + + _mixer = g_mixer; + _mixer->setupPremix(this, premix_proc); + return 0; +} + +void MidiDriver_ADLIB::close() +{ + int i; + for (i = 0; i < ARRAYSIZE(_midi_channels); ++i) { + if (_midi_channels [i]._part) + mc_off (&_midi_channels [i]); + } + + // Detach the premix callback handler + _mixer->setupPremix (0, 0); +} + +void MidiDriver_ADLIB::send (uint32 b) +{ + if (_mode != MO_SIMPLE) + error("MidiDriver_ADLIB::send called but driver is not in simple mode"); + + MidiChannelAdl *mc; + + byte param3 = (byte) ((b >> 24) & 0xFF); + byte param2 = (byte) ((b >> 16) & 0xFF); + byte param1 = (byte) ((b >> 8) & 0xFF); + byte cmd = (byte) (b & 0xF0); + byte chan = (byte) (b & 0x0F); + AdlibPart *part = &_parts [chan]; + + switch (cmd) { + case 0x80:// Note Off + part_key_off (chan, param1); + break; + + case 0x90: // Note On + part_key_on (chan, param1, param2); + break; + + case 0xA0: // Aftertouch + // Not supported. + break; + + case 0xB0: // Control Change + switch (param1) { + case 01: // Modulation wheel + part->_modwheel = param2; + for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { + if (mc->_s10a.active && mc->_s11a.flag0x40) + mc->_s10a.modwheel = part->_modwheel >> 2; + if (mc->_s10b.active && mc->_s11b.flag0x40) + mc->_s10b.modwheel = part->_modwheel >> 2; + } + break; + + case 07: // Volume + part->_vol_eff = param2; + for (mc = part->_mc; mc; mc = mc->_next) { + adlib_set_param(mc->_channel, 0, volume_table[lookup_table[mc->_vol_2][part->_vol_eff >> 2]]); + if (mc->_twochan) { + adlib_set_param(mc->_channel, 13, volume_table[lookup_table[mc->_vol_1][part->_vol_eff >> 2]]); + } + } + break; + + case 10: // Pan position + // Not supported in Adlib (OPL2) + break; + + case 16: // Pitchbend factor + part->_pitchbend_factor = param2; + for (mc = part->_mc; mc; mc = mc->_next) { + adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff, + (part->_pitchbend * part->_pitchbend_factor >> 6) + part->_detune_eff); + } + break; + + case 17: // GP slider 2 (detune) + part->_detune_eff = param2; + for (mc = part->_mc; mc; mc = mc->_next) { + adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff, + (part->_pitchbend * part->_pitchbend_factor >> 6) + part->_detune_eff); + } + break; + + case 18: // GP slider 3 (priority) + part->_pri_eff = param2; + break; + + case 64: // Sustain pedal + part->_pedal = (param2 > 0); + if (!part->_pedal) { + for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { + if (mc->_waitforpedal) + mc_off(mc); + } + } + break; + + case 91: // Effects level + // Not supported in Adlib (OPL2) + break; + + case 93: // Chorus + // Not supported in Adlib (OPL2) + break; + + case 123: // All Notes Off + while (part->_mc) + mc_off (part->_mc); + break; + + default: + warning ("MidiDriver_ADLIB: Unknown control change message %d", param1); + } + break; + + case 0xC0: // Program Change + if (chan != 9) { + if (!map_gm_to_fm [part->_program][0]) + warning ("No Adlib instrument defined for GM program %d", (int) param1); + part->_program = param1; + part_set_instrument (&_parts[chan], (Instrument *) &map_gm_to_fm[part->_program]); + } + break; + + case 0xD0: // Channel Pressure + // Not supported. + break; + + case 0xE0: // Pitch Bend + part->_pitchbend = (param1 | (param2 << 7)) - 0x2000; + for (mc = part->_mc; mc; mc = mc->_next) { + adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff, + (part->_pitchbend * part->_pitchbend_factor >> 6) + part->_detune_eff); + } + break; + + case 0xF0: // SysEx + // We should never get here! SysEx information has to be + // sent via high-level semantic methods. + warning ("MidiDriver_ADLIB: Receiving SysEx command on a send() call"); + break; + + default: + warning ("MidiDriver_ADLIB: Unknown send() command 0x%02X", cmd); + } +} + +void MidiDriver_ADLIB::setPitchBendRange (byte channel, uint range) +{ + MidiChannelAdl *mc; + AdlibPart *part = &_parts [channel]; + + part->_pitchbend_factor = range; + for (mc = part->_mc; mc; mc = mc->_next) { + adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff, + (part->_pitchbend * part->_pitchbend_factor >> 6) + part->_detune_eff); + } +} + +void MidiDriver_ADLIB::sysEx_customInstrument (byte channel, uint32 type, byte *instr) +{ + if (type == 'ADL ') { + Instrument *i = &_parts[channel]._part_instr; + memcpy(i, instr, sizeof(Instrument)); + } +} + +void MidiDriver_ADLIB::setTimerCallback (void *timer_param, void (*timer_proc) (void *)) +{ + _timer_proc = (TimerCallback *) timer_proc; + _timer_param = timer_param; +} + +MidiDriver *MidiDriver_ADLIB_create() +{ + return new MidiDriver_ADLIB(); +} + + + +// All the code brought over from IMuseAdlib + +void MidiDriver_ADLIB::premix_proc(void *param, int16 *buf, uint len) +{ + ((MidiDriver_ADLIB *) param)->generate_samples(buf, len); +} + +void MidiDriver_ADLIB::adlib_write(byte port, byte value) +{ + if (_adlib_reg_cache[port] == value) + return; + _adlib_reg_cache[port] = value; + + OPLWriteReg(_opl, port, value); +} + +void MidiDriver_ADLIB::generate_samples(int16 *data, int len) +{ + int step; + + if (!_opl) { + memset(data, 0, len * sizeof(int16)); + return; + } + + do { + step = len; + if (step > _next_tick) + step = _next_tick; + YM3812UpdateOne(_opl, data, step); + + if (!(_next_tick -= step)) { + if (_timer_proc) + (*_timer_proc) (_timer_param); + on_timer(); + reset_tick(); + } + data += step; + } while (len -= step); +} + +void MidiDriver_ADLIB::reset_tick() +{ + _next_tick = 88; +} + +void MidiDriver_ADLIB::on_timer() +{ + MidiChannelAdl *mc; + int i; + + _adlib_timer_counter += 0xD69; + while (_adlib_timer_counter >= 0x411B) { + _adlib_timer_counter -= 0x411B; + mc = _midi_channels; + for (i = 0; i != ARRAYSIZE(_midi_channels); i++, mc++) { + if (!mc->_part) + continue; + if (mc->_duration && (mc->_duration -= 0x11) <= 0) { + mc_off(mc); + return; + } + if (mc->_s10a.active) { + mc_inc_stuff(mc, &mc->_s10a, &mc->_s11a); + } + if (mc->_s10b.active) { + mc_inc_stuff(mc, &mc->_s10b, &mc->_s11b); + } + } + } +} + +void MidiDriver_ADLIB::mc_off(MidiChannelAdl * mc2) +{ + MidiChannelAdl *mc = (MidiChannelAdl *)mc2, *tmp; + + adlib_key_off(mc->_channel); + + tmp = mc->_prev; + + if (mc->_next) + mc->_next->_prev = tmp; + if (tmp) + tmp->_next = mc->_next; + else + mc->_part->_mc = mc->_next; + mc->_part = NULL; +} + +void MidiDriver_ADLIB::mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11 * s11) +{ + byte code; + AdlibPart *part = mc->_part; + + code = struct10_ontimer(s10, s11); + + if (code & 1) { + switch (s11->param) { + case 0: + mc->_vol_2 = s10->start_value + s11->modify_val; + ((MidiDriver_ADLIB *) part->_drv)->adlib_set_param(mc->_channel, 0, + volume_table[lookup_table[mc->_vol_2] + [part->_vol_eff >> 2]]); + break; + case 13: + mc->_vol_1 = s10->start_value + s11->modify_val; + if (mc->_twochan) { + ((MidiDriver_ADLIB *) part->_drv)->adlib_set_param(mc->_channel, 13, + volume_table[lookup_table[mc->_vol_1] + [part->_vol_eff >> 2]]); + } else { + ((MidiDriver_ADLIB *) part->_drv)->adlib_set_param(mc->_channel, 13, mc->_vol_1); + } + break; + case 30: + s11->s10->modwheel = (char)s11->modify_val; + break; + case 31: + s11->s10->unk3 = (char)s11->modify_val; + break; + default: + ((MidiDriver_ADLIB *) part->_drv)->adlib_set_param(mc->_channel, s11->param, + s10->start_value + s11->modify_val); + break; + } + } + + if (code & 2 && s11->flag0x10) + ((MidiDriver_ADLIB *) part->_drv)->adlib_key_onoff(mc->_channel); +} + +void MidiDriver_ADLIB::adlib_key_off(int chan) +{ + byte port = chan + 0xB0; + adlib_write(port, adlib_read(port) & ~0x20); +} + +byte MidiDriver_ADLIB::struct10_ontimer(Struct10 * s10, Struct11 * s11) +{ + byte result = 0; + int i; + + if (s10->count && (s10->count -= 17) <= 0) { + s10->active = 0; + return 0; + } + + i = s10->cur_val + s10->speed_hi; + s10->speed_lo_counter += s10->speed_lo; + if (s10->speed_lo_counter >= s10->speed_lo_max) { + s10->speed_lo_counter -= s10->speed_lo_max; + i += s10->direction; + } + if (s10->cur_val != i || s10->modwheel != s10->modwheel_last) { + s10->cur_val = i; + s10->modwheel_last = s10->modwheel; + i = lookup_volume(i, s10->modwheel_last); + if (i != s11->modify_val) { + s11->modify_val = i; + result = 1; + } + } + + if (!--s10->num_steps) { + s10->active++; + if (s10->active > 4) { + if (s10->loop) { + s10->active = 1; + result |= 2; + struct10_setup(s10); + } else { + s10->active = 0; + } + } else { + struct10_setup(s10); + } + } + + return result; +} + +void MidiDriver_ADLIB::adlib_set_param(int channel, byte param, int value) +{ + const AdlibSetParams *as; + byte port; + + assert(channel >= 0 && channel < 9); + + if (param <= 12) { + port = channel_mappings_2[channel]; + } else if (param <= 25) { + param -= 13; + port = channel_mappings[channel]; + } else if (param <= 27) { + param -= 13; + port = channel; + } else if (param == 28 || param == 29) { + if (param == 28) + value -= 15; + else + value -= 383; + value <<= 4; + channel_table_2[channel] = value; + adlib_playnote(channel, curnote_table[channel] + value); + return; + } else { + return; + } + + as = &adlib_setparam_table[param]; + if (as->d) + value = as->d - value; + port += as->a; + adlib_write(port, (adlib_read(port) & ~as->c) | (((byte)value) << as->b)); +} + +void MidiDriver_ADLIB::adlib_key_onoff(int channel) +{ + byte val; + byte port = channel + 0xB0; + assert(channel >= 0 && channel < 9); + + val = adlib_read(port); + adlib_write(port, val & ~0x20); + adlib_write(port, val | 0x20); +} + +void MidiDriver_ADLIB::struct10_setup(Struct10 * s10) +{ + int b, c, d, e, f, g, h; + byte t; + + b = s10->unk3; + f = s10->active - 1; + + t = s10->table_a[f]; + e = num_steps_table[lookup_table[t & 0x7F][b]]; + if (t & 0x80) { + e = random_nr(e); + } + if (e == 0) + e++; + + s10->num_steps = s10->speed_lo_max = e; + + if (f != 2) { + c = s10->param; + g = s10->start_value; + t = s10->table_b[f]; + d = lookup_volume(c, (t & 0x7F) - 31); + if (t & 0x80) { + d = random_nr(d); + } + if (d + g > c) { + h = c - g; + } else { + h = d; + if (d + g < 0) + h = -g; + } + h -= s10->cur_val; + } else { + h = 0; + } + + s10->speed_hi = h / e; + if (h < 0) { + h = -h; + s10->direction = -1; + } else { + s10->direction = 1; + } + + s10->speed_lo = h % e; + s10->speed_lo_counter = 0; +} + +void MidiDriver_ADLIB::adlib_playnote(int channel, int note) +{ + byte old, oct, notex; + int note2; + int i; + + note2 = (note >> 7) - 4; + + oct = octave_numbers[note2] << 2; + notex = note_numbers[note2]; + + old = adlib_read(channel + 0xB0); + if (old & 0x20) { + old &= ~0x20; + if (oct > old) { + if (notex < 6) { + notex += 12; + oct -= 4; + } + } else if (oct < old) { + if (notex > 11) { + notex -= 12; + oct += 4; + } + } + } + + i = (notex << 3) + ((note >> 4) & 0x7); + adlib_write(channel + 0xA0, note_to_f_num[i]); + adlib_write(channel + 0xB0, oct | 0x20); +} + +int MidiDriver_ADLIB::random_nr(int a) +{ + static byte _rand_seed = 1; + if (_rand_seed & 1) { + _rand_seed >>= 1; + _rand_seed ^= 0xB8; + } else { + _rand_seed >>= 1; + } + return _rand_seed * a >> 8; +} + +void MidiDriver_ADLIB::part_key_off (byte chan, byte note) +{ + MidiChannelAdl *mc; + + // Percussion is not implemented; filter that channel + if (chan == 9) + return; + + AdlibPart *part; + for (part = _parts; part; part = part->_next) { + if (part->_chan == chan) + break; + } + if (!part) + return; + + for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { + if (mc->_note == note) { + if (part->_pedal) + mc->_waitforpedal = true; + else + mc_off(mc); + } + } +} + +void MidiDriver_ADLIB::part_key_on (byte chan, byte note, byte velocity) +{ + MidiChannelAdl *mc; + + // Percussion is not implemented; filter that channel + if (chan == 9) + return; + + AdlibPart *part; + for (part = _parts; part; part = part->_next) { + if (part->_chan == chan) + break; + } + if (!part) + return; + + mc = allocate_midichan(part->_pri_eff); + if (!mc) + return; + + link_mc(part, mc); + mc_key_on(mc, note, velocity); +} + +MidiChannelAdl *MidiDriver_ADLIB::allocate_midichan(byte pri) +{ + MidiChannelAdl *ac, *best = NULL; + int i; + + for (i = 0; i < 9; i++) { + if (++_midichan_index >= 9) + _midichan_index = 0; + ac = &_midi_channels[_midichan_index]; + if (!ac->_part) + return ac; + if (!ac->_next) { + if (ac->_part->_pri_eff <= pri) { + pri = ac->_part->_pri_eff; + best = ac; + } + } + } + + if (best) + mc_off(best); + return best; +} + +void MidiDriver_ADLIB::link_mc (AdlibPart *part, MidiChannelAdl *mc) +{ + mc->_part = part; + mc->_next = (MidiChannelAdl *)part->_mc; + part->_mc = mc; + mc->_prev = NULL; + + if (mc->_next) + mc->_next->_prev = mc; +} + +void MidiDriver_ADLIB::mc_key_on (MidiChannelAdl * mc2, byte note, byte velocity) +{ + MidiChannelAdl *mc = (MidiChannelAdl *)mc2; + AdlibPart *part = mc->_part; + Instrument *instr = &part->_part_instr; + int c; + byte vol_1, vol_2; + + mc->_twochan = instr->feedback & 1; + mc->_note = note; + mc->_waitforpedal = false; + mc->_duration = instr->duration; + if (mc->_duration != 0) + mc->_duration *= 63; + + vol_1 = (instr->oplvl_1 & 0x3F) + lookup_table[velocity >> 1][instr->waveform_1 >> 2]; + if (vol_1 > 0x3F) + vol_1 = 0x3F; + mc->_vol_1 = vol_1; + + vol_2 = (instr->oplvl_2 & 0x3F) + lookup_table[velocity >> 1][instr->waveform_2 >> 2]; + if (vol_2 > 0x3F) + vol_2 = 0x3F; + mc->_vol_2 = vol_2; + + c = part->_vol_eff >> 2; + + vol_2 = volume_table[lookup_table[vol_2][c]]; + if (mc->_twochan) + vol_1 = volume_table[lookup_table[vol_1][c]]; + + adlib_setup_channel(mc->_channel, instr, vol_1, vol_2); + adlib_note_on_ex(mc->_channel, part->_transpose_eff + note, part->_detune_eff + (part->_pitchbend * part->_pitchbend_factor >> 6)); + + if (instr->flags_a & 0x80) { + mc_init_stuff(mc, &mc->_s10a, &mc->_s11a, instr->flags_a, &instr->extra_a); + } else { + mc->_s10a.active = 0; + } + + if (instr->flags_b & 0x80) { + mc_init_stuff(mc, &mc->_s10b, &mc->_s11b, instr->flags_b, &instr->extra_b); + } else { + mc->_s10b.active = 0; + } +} + +void MidiDriver_ADLIB::adlib_setup_channel(int chan, Instrument * instr, byte vol_1, byte vol_2) +{ + byte port; + + assert(chan >= 0 && chan < 9); + + port = channel_mappings[chan]; + adlib_write(port + 0x20, instr->flags_1); + + // FIXME: Without using g_scumm, this may make older games sound weird. + // Gotta transform the volume *before* it gets sent here. + if (/*!(g_scumm->_features & GF_SMALL_HEADER)*/true ||(instr->feedback & 1)) + adlib_write(port + 0x40, (instr->oplvl_1 | 0x3F) - vol_1 ); + else + adlib_write(port + 0x40, instr->oplvl_1); + + adlib_write(port + 0x60, 0xff & (~instr->atdec_1)); + adlib_write(port + 0x80, 0xff & (~instr->sustrel_1)); + adlib_write(port + 0xE0, instr->waveform_1); + + port = channel_mappings_2[chan]; + adlib_write(port + 0x20, instr->flags_2); + adlib_write(port + 0x40, (instr->oplvl_2 | 0x3F) - vol_2 ); + adlib_write(port + 0x60, 0xff & (~instr->atdec_2)); + adlib_write(port + 0x80, 0xff & (~instr->sustrel_2)); + adlib_write(port + 0xE0, instr->waveform_2); + + adlib_write((byte)chan + 0xC0, instr->feedback); +} + +void MidiDriver_ADLIB::adlib_note_on_ex(int chan, byte note, int mod) +{ + int code; + assert(chan >= 0 && chan < 9); + code = (note << 7) + mod; + curnote_table[chan] = code; + channel_table_2[chan] = 0; + adlib_playnote(chan, code); +} + +void MidiDriver_ADLIB::mc_init_stuff (MidiChannelAdl *mc, Struct10 * s10, + Struct11 * s11, byte flags, InstrumentExtra * ie) +{ + AdlibPart *part = mc->_part; + + s11->modify_val = 0; + s11->flag0x40 = flags & 0x40; + s10->loop = flags & 0x20; + s11->flag0x10 = flags & 0x10; + s11->param = param_table_1[flags & 0xF]; + s10->param = param_table_2[flags & 0xF]; + s10->unk3 = 31; + if (s11->flag0x40) { + s10->modwheel = part->_modwheel >> 2; + } else { + s10->modwheel = 31; + } + + switch (s11->param) { + case 0: + s10->start_value = mc->_vol_2; + break; + case 13: + s10->start_value = mc->_vol_1; + break; + case 30: + s10->start_value = 31; + s11->s10->modwheel = 0; + break; + case 31: + s10->start_value = 0; + s11->s10->unk3 = 0; + break; + default: + s10->start_value = ((MidiDriver_ADLIB *) part->_drv)->adlib_read_param(mc->_channel, s11->param); + } + + struct10_init(s10, ie); +} + +void MidiDriver_ADLIB::struct10_init(Struct10 * s10, InstrumentExtra * ie) +{ + s10->active = 1; + s10->cur_val = 0; + s10->modwheel_last = 31; + s10->count = ie->a; + if (s10->count) + s10->count *= 63; + s10->table_a[0] = ie->b; + s10->table_a[1] = ie->d; + s10->table_a[2] = ie->f; + s10->table_a[3] = ie->g; + + s10->table_b[0] = ie->c; + s10->table_b[1] = ie->e; + s10->table_b[2] = 0; + s10->table_b[3] = ie->h; + + struct10_setup(s10); +} + +int MidiDriver_ADLIB::adlib_read_param(int chan, byte param) +{ + const AdlibSetParams *as; + byte val; + byte port; + + assert(chan >= 0 && chan < 9); + + if (param <= 12) { + port = channel_mappings_2[chan]; + } else if (param <= 25) { + param -= 13; + port = channel_mappings[chan]; + } else if (param <= 27) { + param -= 13; + port = chan; + } else if (param == 28) { + return 0xF; + } else if (param == 29) { + return 0x17F; + } else { + return 0; + } + + as = &adlib_setparam_table[param]; + val = adlib_read(port + as->a); + val &= as->c; + val >>= as->b; + if (as->d) + val = as->d - val; + + return val; +} + +void MidiDriver_ADLIB::adlib_note_on(int chan, byte note, int mod) +{ + int code; + assert(chan >= 0 && chan < 9); + code = (note << 7) + mod; + curnote_table[chan] = code; + adlib_playnote(chan, channel_table_2[chan] + code); +} + +void MidiDriver_ADLIB::part_set_instrument(AdlibPart *part, Instrument * instr) +{ + Instrument *i = &part->_part_instr; + memcpy(i, instr, sizeof(Instrument)); +} |