vgm-conv
Version:
Chip-type and clock converter for VGM.
162 lines (161 loc) • 6.58 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.YM2608ToOPMConverter = exports.YM2203ToOPMConverter = exports.YM2612ToOPMConverter = exports.OPNToOPMConverter = void 0;
const vgm_converter_1 = require("./vgm-converter");
const vgm_parser_1 = require("vgm-parser");
const vgm_write_data_buffer_1 = __importDefault(require("./vgm-write-data-buffer"));
const opm_freq_1 = require("./opm_freq");
const ay8910_to_opm_coverter_1 = require("./ay8910-to-opm-coverter");
class OPNToOPMConverter extends vgm_converter_1.VGMConverter {
opts;
_regs = [new Uint8Array(256), new Uint8Array(256)];
_buf = new vgm_write_data_buffer_1.default(256, 1);
_clockRatio;
_lrCache = [0, 0, 0, 0, 0, 0, 0, 0];
_clockDiv;
constructor(from, to, opts) {
super(from, to);
this.opts = opts;
this._clockRatio = 3579545 / this.convertedChipInfo.clock;
this._clockDiv = from.chip == "ym2203" ? 1.0 : 2.0;
}
_y(addr, data, optimize = true) {
const index = this.from.index;
this._buf.push(new vgm_parser_1.VGMWriteDataCommand({ target: vgm_parser_1.VGMWriteDataTargetId.ym2151, index, port: 0, addr, data }), optimize);
}
_fnumToFreq(fnum, blk) {
return (fnum * this.from.clock) / ((72 * this._clockDiv) << (20 - blk));
}
_fnumToNote(fnum, blk) {
const freq = this._fnumToFreq(fnum, blk);
return (0, opm_freq_1.freqToOPMNote)(freq, this._clockRatio);
}
convertFM(cmd) {
const adr = cmd.addr;
const regs = this._regs[cmd.port];
regs[adr] = cmd.data;
if (cmd.port == 0) {
if (adr == 0x22 && this.from.chip != "ym2203") {
const lfreq = [0xc2, 0xc9, 0xcb, 0xcd, 0xcf, 0xd6, 0xfb, 0xff][cmd.data & 7];
this._y(0x18, lfreq);
}
else if (adr == 0x28) {
const ch = cmd.data & 0x7;
const slots = (cmd.data & 0xf0) >> 4;
this._y(0x08, (slots << 3) | ch, false);
}
}
if (0x30 <= adr && adr <= 0x8f) {
const nch = adr & 3;
const ch = (cmd.port == 0 ? 0 : 4) + nch;
const slot = (adr >> 2) & 3;
const base = 0x40 + ((adr & 0xf0) - 0x30) * 2;
const offset = slot * 8 + ch;
this._y(base + offset, cmd.data);
}
// FB CON
if (0xb0 <= adr && adr <= 0xb2) {
const nch = adr & 3;
const ch = (cmd.port == 0 ? 0 : 4) + nch;
// L R FB CON
this._y(0x20 + ch, (this.getRLFlags(ch) << 6) | (cmd.data & 0x3f));
}
// L R AMS PMS
if (0xb4 <= adr && adr <= 0xb6) {
const nch = adr & 3;
const ch = (cmd.port == 0 ? 0 : 4) + nch;
this._lrCache[ch] = (cmd.data >> 6) & 0x3;
const ams = (cmd.data >> 4) & 0x3;
const pms = cmd.data & 0x7;
// PMS AMS
this._y(0x38 + ch, (pms << 4) | ams);
// L R FB CON
this._y(0x20 + ch, (this.getRLFlags(ch) << 6) | (regs[0xb0 + nch] & 0x3f));
}
// F-Number and Block
if ((0xa0 <= adr && adr <= 0xa2) || (0xa4 <= adr && adr < 0xa6)) {
const nch = adr & 3;
const ch = (cmd.port == 0 ? 0 : 4) + nch;
const al = 0xa0 + nch;
const ah = 0xa4 + nch;
const fnum = (((regs[ah] & 7) << 8) | regs[al]) >> 2;
const blk = (regs[ah] >> 3) & 7;
const { kc, kf } = this._fnumToNote(fnum, blk);
this._y(0x28 + ch, kc);
this._y(0x30 + ch, kf << 2);
}
return this._buf.commit();
}
getRLFlags(ch) {
if (this.from.chip == "ym2203") {
return 3;
}
const lr = this._lrCache[ch];
return ((lr & 1) << 1) | ((lr >> 1) & 1);
}
getInitialCommands() {
this._y(0x18, 0xc2); // LFO FREQ
return this._buf.commit();
}
convertCommand(cmd) {
const convertFM = this.from.subModule == null || this.from.subModule === "fm";
if (cmd instanceof vgm_parser_1.VGMWriteDataCommand && cmd.chip === this.from.chip && cmd.index === this.from.index) {
if (cmd.addr < 0x10 && cmd.port === 0) {
// Not Supported
return [cmd];
}
else {
if (convertFM) {
if (this.from.subModule == "fm" && cmd.addr == 0x2b) {
return [cmd]; // Pass through YM2612 DAC access
}
return this.convertFM(cmd);
}
}
}
return [cmd];
}
}
exports.OPNToOPMConverter = OPNToOPMConverter;
class YM2612ToOPMConverter extends OPNToOPMConverter {
constructor(from, to, opts) {
super(from, { chip: "ym2151", index: from.index, clock: 1 / 2, relativeClock: true }, opts);
}
}
exports.YM2612ToOPMConverter = YM2612ToOPMConverter;
class YM2203ToOPMConverter extends OPNToOPMConverter {
constructor(from, to, opts) {
const _to = { chip: "ym2151", index: from.index, clock: 1, relativeClock: true };
super(from, _to, opts);
this._ssgConverter = new ay8910_to_opm_coverter_1.AY8910ToOPMConverter(from, _to, {
mainAttenuation: opts?.ssgAttenuation ?? 0,
whiteNoiseAttenuation: opts?.whiteNoiseAttenuation,
squareWaveAttenuation: opts?.squareWaveAttenuation,
});
}
_ssgConverter;
getInitialCommands() {
return [...this._ssgConverter.getInitialCommands(), ...super.getInitialCommands()];
}
convertCommand(cmd) {
const convertSSG = this.from.subModule == null || this.from.subModule == "ssg";
if (cmd instanceof vgm_parser_1.VGMWriteDataCommand && cmd.chip === this.from.chip && cmd.index === this.from.index) {
if (cmd.addr < 0x10 && cmd.port === 0) {
if (convertSSG) {
return this._ssgConverter.convertCommand(cmd);
}
}
}
return super.convertCommand(cmd);
}
}
exports.YM2203ToOPMConverter = YM2203ToOPMConverter;
class YM2608ToOPMConverter extends OPNToOPMConverter {
constructor(from, to, opts) {
super(from, { chip: "ym2151", index: from.index, clock: 1 / 2, relativeClock: true }, opts);
}
}
exports.YM2608ToOPMConverter = YM2608ToOPMConverter;