vgm-conv
Version:
Chip-type and clock converter for VGM.
90 lines (89 loc) • 3.91 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.OPMClockConverter = 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 keyCodeToIndex = [0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12];
const keyIndexToCode = [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14];
class OPMClockConverter extends vgm_converter_1.VGMClockConverter {
_ratio;
_regs = new Uint8Array(256);
_buf = new vgm_write_data_buffer_1.default(256, 1);
_keyDiff = 0;
_lfoDiff = 0;
constructor(from, toClock, opts) {
super(from, toClock, 3579545);
this._ratio = this.to.clock / from.clock;
this._keyDiff = Math.round(12 * Math.log2(1.0 / this._ratio) * 256);
/* LFO_FREQ = CLOCK * POWER(2, LFRQ/16 - 32) = CLOCK' * POWER(2, LFRQ'/16 - 32) */
/* => LFRQ' = 16 * LOG2(CLOCK/CLOCK') + LFRQ */
this._lfoDiff = Math.round(16 * Math.log2(1.0 / this._ratio));
}
_y(addr, data, optimize = true) {
const target = this.from.index ? vgm_parser_1.VGMWriteDataTargetId.ym2151_2 : vgm_parser_1.VGMWriteDataTargetId.ym2151;
const index = this.from.index;
this._buf.push(new vgm_parser_1.VGMWriteDataCommand({ target, index, port: 0, addr, data: data }), optimize);
}
getInitialCommands() {
const lfrq = Math.max(0, Math.min(255, this._lfoDiff));
this._y(0x18, lfrq);
return this._buf.commit();
}
convertWriteDataCommand(cmd) {
if (this._ratio !== 1.0) {
this._regs[cmd.addr] = cmd.data;
if ((0x28 <= cmd.addr && cmd.addr <= 0x2f) || (0x30 <= cmd.addr && cmd.addr <= 0x37)) {
const ch = cmd.addr - (cmd.addr < 0x30 ? 0x28 : 0x30);
const orgKeyIndex = keyCodeToIndex[this._regs[0x28 + ch] & 0xf];
const orgKey = (orgKeyIndex << 8) | (this._regs[0x30 + ch] & 0xfc);
let octave = (this._regs[0x28 + ch] >> 4) & 0x7;
let newKey = orgKey + this._keyDiff;
if (newKey < 0) {
if (0 < octave) {
octave--;
newKey += 12 << 8;
}
else {
newKey = 0;
}
}
else if (newKey >= 12 << 8) {
if (octave < 7) {
octave++;
newKey -= 12 << 8;
}
else {
newKey = (12 << 8) - 1;
}
}
const okc = (octave << 4) | keyIndexToCode[newKey >> 8];
this._y(0x28 + ch, okc);
const kf = newKey & 0xfc;
this._y(0x30 + ch, kf);
return this._buf.commit();
}
else if (cmd.addr === 0x0f) {
const nfrq = Math.min(0x1f, Math.round((cmd.data & 0x1f) * this._ratio));
this._y(cmd.addr, (cmd.data & 0xe0) | nfrq);
return this._buf.commit();
}
else if (cmd.addr === 0x18) {
const lfrq = Math.max(0, Math.min(255, Math.round(this._lfoDiff + cmd.data)));
this._y(cmd.addr, lfrq);
return this._buf.commit();
}
}
return [cmd];
}
convertCommand(cmd) {
if (cmd instanceof vgm_parser_1.VGMWriteDataCommand && cmd.chip === this.to.chip && cmd.index === this.from.index) {
return this.convertWriteDataCommand(cmd);
}
return [cmd];
}
}
exports.OPMClockConverter = OPMClockConverter;