S98 register-log music for retro FM hardware, including the OPNA hardware-rhythm drums.
Extensions: .s98
| S98 device | Core |
|---|---|
| PSG, OPN, OPN2, OPNA, OPM | cisc's fmgen (m_s98/device/fmgen), shared with fmpplugin |
| OPLL | Okazaki's emu2413 |
| SNG (SN76489) | NEZplug tables (s_sng.c) |
| OPL, OPL2, OPL3 | ymfm (m_s98/device/s98_ymfm.cpp) |
Almost the whole corpus is OPNA — of 5,379 .s98 songs only 11 use the OPL
devices at all: nine OPL3 (a Sound Blaster rip) and two OPL2 (the PC-9801
"Sound Orchestra" board).
Replaced MAME's fmopl.cpp + ymf262.cpp (and the s98mame.cpp wrapper),
which were GPL-2.0+. Applied to both variants, not just mas, because it
is also a correctness fix.
The OPL3 high bank was unreachable. m_s98.cpp encodes a port-1 write as
0x100|reg, which for OPL3 selects the second register bank. s98mame.cpp
passed that straight to YMF262Write() as an 8-bit address, and MAME masks the
address latch with v &= 0xff — so every high-bank write landed in bank 0.
Registers 0x105 (OPL3 enable) and 0x104 (4-operator mode) never arrived,
and all nine OPL3 songs played as plain 2-op OPL2. In these files the high bank
is a third of all register traffic (15,835–20,622 writes each). ymfm has a
distinct write_address_hi() and the adapter uses it.
Resampling is ours now. MAME resampled internally — YM3812Init(clock, rate) takes the output rate. ymfm does not: it generates at the chip's native
rate (clock/72 for OPL2, clock/288 for OPL3) and leaves conversion to the
caller. The adapter box-filters down to the output rate; both chips run above it
here (55466 Hz and 50000 Hz vs 44100 Hz), so plain decimation would alias.
Output mapping. OPL2 is mono and feeds both channels. OPL3 has four lanes;
L = 0 + 2, R = 1 + 3, matching what s98mame.cpp did.
Its own ymfm copy. Not shared with libvgmplugin: that target merges its
objects with ld -r, which turns its ymfm template instantiations into private
externs — invisible to other targets, and by the same token unable to collide
with this second copy.
A/B against the old core: OPL2 agrees within 1.6% RMS; OPL3 differs, mostly from the bank fix above.
Built identically in both variants — there is no mas gate. Full terms are in
LEGAL; in short:
- ymfm — BSD-3.
- fmgen — cisc's own terms, which require that distribution be as freeware.
See
fmgen/readme.txt(kept unaltered, as its licence requires) andfmgen/MODIFICATIONS.md. - The OPNA rhythm voices are synthesized, not Yamaha's. The YM2608 ADPCM-A
rhythm ROM has been removed;
fmgen/gen_rhythm_synth.cgenerates the six voices from scratch, matched to the originals in count, order, length and level but not in timbre. An external2608_BD.WAV .. 2608_RIM.WAVset still takes priority, so a user with the real ROM gets authentic drums. - m_s98 itself, and the NEZplug
s_sng.c/s_logtbl.ctables — Mamiya's own terms. The vendored files have no headers, but his upstream manuals do: m_s98.kpi 1.0r10 says to follow each bundled program's licence and "as for the parts I wrote, treat them freely"; NEZplug 0.9.4.8 says the program is freeware and "sources written by Mamiya may be used freely". Unconditional — no copyleft, no noncommercial limit. - emu2413 — MIT. The vendored v0.61 (2004) predates the GitHub repo and has
no header, but upstream's MIT LICENSE is
Copyright (c) 2001-2019and its CHANGELOG lists v0.61 as its own history.
Nothing here is unresolved any more; the binding constraint on the plugin is fmgen's freeware condition.