UNPKG

vgm-conv

Version:
185 lines (184 loc) 6.52 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.YM2413ToOPLConverter = 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 ym_voice_1 = require("ym-voice"); function getModOffset(ch) { return 8 * Math.floor(ch / 3) + (ch % 3); } function _R(rate) { return rate; } function _KLFix(kl) { switch (kl) { case 0: return 0; case 1: return 2; case 2: return 1; default: return 3; } } function type2target(type) { switch (type) { case "ym3526": return vgm_parser_1.VGMWriteDataTargetId.ym3526; // 0x5b; case "y8950": return vgm_parser_1.VGMWriteDataTargetId.y8950; // 0x5c; case "ymf262": return vgm_parser_1.VGMWriteDataTargetId.ymf262_p0; // 0x5e; case "ym3812": default: return vgm_parser_1.VGMWriteDataTargetId.ym3812; // 0x5a; } } class YM2413ToOPLConverter extends vgm_converter_1.VGMConverter { _regs = new Uint8Array(256).fill(0); _buf = new vgm_write_data_buffer_1.default(256, 1); _type; _targetId; _romVoices; _lfoDepth = 3; constructor(from, to, opts) { super(from, { chip: to.chip, index: from.index, clock: to.chip === "ymf262" ? 4 : 1, relativeClock: true }); this._type = to.chip; this._targetId = type2target(this._type); this._romVoices = (0, ym_voice_1.getOPLLRomVoices)(opts?.opllVariant); } _y(addr, data, optimize = true) { const index = this.from.index; this._buf.push(new vgm_parser_1.VGMWriteDataCommand({ target: this._targetId, index, addr, data }), optimize); } getInitialCommands() { this._y(0x01, 0x20); // YM3812 mode this._y(0xbd, this._lfoDepth << 6); // LFO depth return this._buf.commit(); } _writeVoice(ch, v, modVolume, carVolume, key) { const modOffset = getModOffset(ch); const carOffset = modOffset + 3; const mod = v.slots[0]; const car = v.slots[1]; [ { a: 0x20 + modOffset, d: (mod.am << 7) | (mod.pm << 6) | (mod.eg << 5) | (mod.kr << 4) | mod.ml, }, { a: 0x20 + carOffset, d: (car.am << 7) | (car.pm << 6) | (car.eg << 5) | (car.kr << 4) | car.ml, }, { a: 0x40 + modOffset, d: (_KLFix(mod.kl) << 6) | (modVolume ? modVolume : mod.tl), }, { a: 0x40 + carOffset, d: (_KLFix(car.kl) << 6) | (carVolume ? carVolume : car.tl), }, { a: 0x60 + modOffset, d: (_R(mod.ar) << 4) | _R(mod.dr), }, { a: 0x60 + carOffset, d: (_R(car.ar) << 4) | _R(car.dr), }, { a: 0x80 + modOffset, d: (mod.sl << 4) | (!mod.eg ? _R(mod.rr) : 0), }, { a: 0x80 + carOffset, d: (car.sl << 4) | _R(car.eg || key ? _R(car.rr) : _R(6)), }, { a: 0xc0 + ch, d: (this._type === "ymf262" ? 0xf0 : 0) | (v.fb << 1), }, { a: 0xe0 + modOffset, d: mod.ws ? 1 : 0 }, { a: 0xe0 + carOffset, d: car.ws ? 1 : 0 }, ].forEach(({ a, d }) => { this._y(a, d); }); } _rflag = false; _updateVoice(ch) { const d = this._regs[0x30 + ch]; const inst = (d & 0xf0) >> 4; const volume = d & 0xf; const voice = inst === 0 ? ym_voice_1.OPLLVoice.decode(this._regs) : this._romVoices[inst]; const key = this._regs[0x20 + ch] & 0x10 ? true : false; const toTL = (vol, off) => Math.max((vol << 2) - off, 0); if (this._rflag && 6 <= ch) { switch (ch) { case 6: this._writeVoice(6, this._romVoices[16], null, toTL(volume, 0), key); break; case 7: this._writeVoice(7, this._romVoices[17], toTL(inst, 0), toTL(volume, 0), key); break; case 8: this._writeVoice(8, this._romVoices[18], toTL(inst, 0), toTL(volume, 0), key); break; } } else { this._writeVoice(ch, voice, null, toTL(volume, 0), key); } } _convert(cmd) { const a = cmd.addr; const d = cmd.data; this._regs[a & 0xff] = d & 0xff; if (a == 0x0e) { if (d & 0x20 && !this._rflag) { this._rflag = true; this._updateVoice(6); this._updateVoice(7); this._updateVoice(8); } else if (!(d & 0x20) && this._rflag) { this._rflag = false; this._updateVoice(6); this._updateVoice(7); this._updateVoice(8); this._y(0xbd, 0xc0 | (d & 0x3f)); } else { this._rflag = d & 0x20 ? true : false; } this._y(0xbd, (this._lfoDepth << 6) | (d & 0x3f)); } else if (0x10 <= a && a <= 0x18) { const ch = a & 0xf; this._y(0xb0 + ch, ((this._regs[0x20 + ch] & 0x1f) << 1) | ((d & 0x80) >> 7)); this._y(0xa0 + ch, (d & 0x7f) << 1); } else if (0x20 <= a && a <= 0x28) { const ch = a & 0xf; this._updateVoice(ch); this._y(0xb0 + ch, ((d & 0x1f) << 1) | ((this._regs[0x10 + ch] & 0x80) >> 7)); this._y(0xa0 + ch, (this._regs[0x10 + ch] & 0x7f) << 1); } else if (0x30 <= a && a <= 0x38) { const ch = a & 0xf; this._updateVoice(ch); } return this._buf.commit(); } convertCommand(cmd) { if (cmd instanceof vgm_parser_1.VGMWriteDataCommand && cmd.chip === "ym2413" && cmd.index === this.from.index) { return this._convert(cmd); } return [cmd]; } } exports.YM2413ToOPLConverter = YM2413ToOPLConverter;