broken-neees
Version:
A really broken NEEES emulator that introduces glitches and random bugs on purpose!
482 lines (477 loc) • 19.5 kB
JavaScript
"use strict";
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _InMemoryRegister = _interopRequireDefault(require("../lib/InMemoryRegister"));
var _noteLengths = _interopRequireDefault(require("../lib/apu/noteLengths"));
var _byte = _interopRequireDefault(require("../lib/byte"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
var PulseControl = /*#__PURE__*/function (_InMemoryRegister$APU) {
_inherits(PulseControl, _InMemoryRegister$APU);
var _super = _createSuper(PulseControl);
function PulseControl() {
_classCallCheck(this, PulseControl);
return _super.apply(this, arguments);
}
_createClass(PulseControl, [{
key: "onLoad",
value: function onLoad() {
this.addField("volumeOrEnvelopePeriod", 0, 4).addField("constantVolume", 4).addField("envelopeLoopOrLengthCounterHalt", 5).addField("dutyCycleId", 6, 2);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
}
}]);
return PulseControl;
}(_InMemoryRegister.default.APU);
var PulseSweep = /*#__PURE__*/function (_InMemoryRegister$APU2) {
_inherits(PulseSweep, _InMemoryRegister$APU2);
var _super2 = _createSuper(PulseSweep);
function PulseSweep() {
_classCallCheck(this, PulseSweep);
return _super2.apply(this, arguments);
}
_createClass(PulseSweep, [{
key: "onLoad",
value: function onLoad() {
this.addField("shiftCount", 0, 3).addField("negateFlag", 3).addField("dividerPeriodMinusOne", 4, 3).addField("enabledFlag", 7);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
var channel = this.apu.channels.pulses[this.id];
channel.frequencySweep.startFlag = true;
}
}]);
return PulseSweep;
}(_InMemoryRegister.default.APU);
var PulseTimerLow = /*#__PURE__*/function (_InMemoryRegister$APU3) {
_inherits(PulseTimerLow, _InMemoryRegister$APU3);
var _super3 = _createSuper(PulseTimerLow);
function PulseTimerLow() {
_classCallCheck(this, PulseTimerLow);
return _super3.apply(this, arguments);
}
_createClass(PulseTimerLow, [{
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
var channel = this.apu.channels.pulses[this.id];
channel.updateTimer();
}
}]);
return PulseTimerLow;
}(_InMemoryRegister.default.APU);
var PulseTimerHighLCL = /*#__PURE__*/function (_InMemoryRegister$APU4) {
_inherits(PulseTimerHighLCL, _InMemoryRegister$APU4);
var _super4 = _createSuper(PulseTimerHighLCL);
function PulseTimerHighLCL() {
_classCallCheck(this, PulseTimerHighLCL);
return _super4.apply(this, arguments);
}
_createClass(PulseTimerHighLCL, [{
key: "onLoad",
value: function onLoad() {
this.addField("timerHigh", 0, 3).addField("lengthCounterLoad", 3, 5);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
var channel = this.apu.channels.pulses[this.id];
channel.updateTimer();
channel.lengthCounter.counter = _noteLengths.default[this.lengthCounterLoad];
channel.volumeEnvelope.startFlag = true;
}
}]);
return PulseTimerHighLCL;
}(_InMemoryRegister.default.APU);
var TriangleLengthControl = /*#__PURE__*/function (_InMemoryRegister$APU5) {
_inherits(TriangleLengthControl, _InMemoryRegister$APU5);
var _super5 = _createSuper(TriangleLengthControl);
function TriangleLengthControl() {
_classCallCheck(this, TriangleLengthControl);
return _super5.apply(this, arguments);
}
_createClass(TriangleLengthControl, [{
key: "onLoad",
value: function onLoad() {
this.addField("linearCounterReload", 0, 7).addField("halt", 7, 1);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
this.apu.channels.triangle.linearLengthCounter.reload = this.linearCounterReload;
}
}]);
return TriangleLengthControl;
}(_InMemoryRegister.default.APU);
var TriangleTimerLow = /*#__PURE__*/function (_InMemoryRegister$APU6) {
_inherits(TriangleTimerLow, _InMemoryRegister$APU6);
var _super6 = _createSuper(TriangleTimerLow);
function TriangleTimerLow() {
_classCallCheck(this, TriangleTimerLow);
return _super6.apply(this, arguments);
}
_createClass(TriangleTimerLow, [{
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
}
}]);
return TriangleTimerLow;
}(_InMemoryRegister.default.APU);
var TriangleTimerHighLCL = /*#__PURE__*/function (_InMemoryRegister$APU7) {
_inherits(TriangleTimerHighLCL, _InMemoryRegister$APU7);
var _super7 = _createSuper(TriangleTimerHighLCL);
function TriangleTimerHighLCL() {
_classCallCheck(this, TriangleTimerHighLCL);
return _super7.apply(this, arguments);
}
_createClass(TriangleTimerHighLCL, [{
key: "onLoad",
value: function onLoad() {
this.addField("timerHigh", 0, 3).addField("lengthCounterLoad", 3, 5);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
var triangle = this.apu.channels.triangle;
triangle.lengthCounter.counter = _noteLengths.default[this.lengthCounterLoad];
triangle.linearLengthCounter.reloadFlag = true;
}
}]);
return TriangleTimerHighLCL;
}(_InMemoryRegister.default.APU);
var NoiseControl = /*#__PURE__*/function (_InMemoryRegister$APU8) {
_inherits(NoiseControl, _InMemoryRegister$APU8);
var _super8 = _createSuper(NoiseControl);
function NoiseControl() {
_classCallCheck(this, NoiseControl);
return _super8.apply(this, arguments);
}
_createClass(NoiseControl, [{
key: "onLoad",
value: function onLoad() {
this.addField("volumeOrEnvelopePeriod", 0, 4).addField("constantVolume", 4).addField("envelopeLoopOrLengthCounterHalt", 5);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
}
}]);
return NoiseControl;
}(_InMemoryRegister.default.APU);
var NoiseForm = /*#__PURE__*/function (_InMemoryRegister$APU9) {
_inherits(NoiseForm, _InMemoryRegister$APU9);
var _super9 = _createSuper(NoiseForm);
function NoiseForm() {
_classCallCheck(this, NoiseForm);
return _super9.apply(this, arguments);
}
_createClass(NoiseForm, [{
key: "onLoad",
value: function onLoad() {
this.addField("periodId", 0, 4).addField("mode", 7);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
}
}]);
return NoiseForm;
}(_InMemoryRegister.default.APU);
var NoiseLCL = /*#__PURE__*/function (_InMemoryRegister$APU10) {
_inherits(NoiseLCL, _InMemoryRegister$APU10);
var _super10 = _createSuper(NoiseLCL);
function NoiseLCL() {
_classCallCheck(this, NoiseLCL);
return _super10.apply(this, arguments);
}
_createClass(NoiseLCL, [{
key: "onLoad",
value: function onLoad() {
this.addField("lengthCounterLoad", 3, 5);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
var channel = this.apu.channels.noise;
channel.lengthCounter.counter = _noteLengths.default[this.lengthCounterLoad];
channel.volumeEnvelope.startFlag = true;
}
}]);
return NoiseLCL;
}(_InMemoryRegister.default.APU);
var DMCControl = /*#__PURE__*/function (_InMemoryRegister$APU11) {
_inherits(DMCControl, _InMemoryRegister$APU11);
var _super11 = _createSuper(DMCControl);
function DMCControl() {
_classCallCheck(this, DMCControl);
return _super11.apply(this, arguments);
}
_createClass(DMCControl, [{
key: "onLoad",
value: function onLoad() {
this.addField("dpcmPeriodId", 0, 4).addField("loop", 6);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
}
}]);
return DMCControl;
}(_InMemoryRegister.default.APU);
var DMCLoad = /*#__PURE__*/function (_InMemoryRegister$APU12) {
_inherits(DMCLoad, _InMemoryRegister$APU12);
var _super12 = _createSuper(DMCLoad);
function DMCLoad() {
_classCallCheck(this, DMCLoad);
return _super12.apply(this, arguments);
}
_createClass(DMCLoad, [{
key: "onLoad",
value: function onLoad() {
this.addField("directLoad", 0, 7);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
var apu = this.apu;
apu.channels.dmc.outputSample = this.directLoad;
}
}]);
return DMCLoad;
}(_InMemoryRegister.default.APU);
var DMCSampleAddress = /*#__PURE__*/function (_InMemoryRegister$APU13) {
_inherits(DMCSampleAddress, _InMemoryRegister$APU13);
var _super13 = _createSuper(DMCSampleAddress);
function DMCSampleAddress() {
_classCallCheck(this, DMCSampleAddress);
return _super13.apply(this, arguments);
}
_createClass(DMCSampleAddress, [{
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
}
}]);
return DMCSampleAddress;
}(_InMemoryRegister.default.APU);
var DMCSampleLength = /*#__PURE__*/function (_InMemoryRegister$APU14) {
_inherits(DMCSampleLength, _InMemoryRegister$APU14);
var _super14 = _createSuper(DMCSampleLength);
function DMCSampleLength() {
_classCallCheck(this, DMCSampleLength);
return _super14.apply(this, arguments);
}
_createClass(DMCSampleLength, [{
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
}
}]);
return DMCSampleLength;
}(_InMemoryRegister.default.APU);
var APUStatus = /*#__PURE__*/function (_InMemoryRegister$APU15) {
_inherits(APUStatus, _InMemoryRegister$APU15);
var _super15 = _createSuper(APUStatus);
function APUStatus() {
_classCallCheck(this, APUStatus);
return _super15.apply(this, arguments);
}
_createClass(APUStatus, [{
key: "onRead",
value: function onRead() {
var apu = this.apu;
var channels = apu.channels;
return _byte.default.bitfield(+(channels.pulses[0].lengthCounter.counter > 0), +(channels.pulses[1].lengthCounter.counter > 0), +(channels.triangle.lengthCounter.counter > 0), +(channels.noise.lengthCounter.counter > 0), channels.dmc.dpcm.remainingBytes() > 0, 0, 0, 0);
}
}]);
return APUStatus;
}(_InMemoryRegister.default.APU);
var APUControl = /*#__PURE__*/function (_InMemoryRegister$APU16) {
_inherits(APUControl, _InMemoryRegister$APU16);
var _super16 = _createSuper(APUControl);
function APUControl() {
_classCallCheck(this, APUControl);
return _super16.apply(this, arguments);
}
_createClass(APUControl, [{
key: "onLoad",
value: function onLoad() {
this.addField("enablePulse1", 0).addField("enablePulse2", 1).addField("enableTriangle", 2).addField("enableNoise", 3).addField("enableDMC", 4);
}
}, {
key: "onWrite",
value: function onWrite(value) {
var channels = this.apu.channels;
this.setValue(value);
var enablePulse1 = this.enablePulse1,
enablePulse2 = this.enablePulse2,
enableTriangle = this.enableTriangle,
enableNoise = this.enableNoise,
enableDMC = this.enableDMC;
if (!enablePulse1) channels.pulses[0].lengthCounter.reset();
if (!enablePulse2) channels.pulses[1].lengthCounter.reset();
if (!enableTriangle) {
channels.triangle.lengthCounter.reset();
channels.triangle.linearLengthCounter.fullReset();
}
if (!enableNoise) channels.noise.lengthCounter.reset();
if (!enableDMC) channels.dmc.dpcm.stop();else if (channels.dmc.dpcm.remainingBytes() === 0) channels.dmc.dpcm.start();
}
}]);
return APUControl;
}(_InMemoryRegister.default.APU);
var APUFrameCounter = /*#__PURE__*/function (_InMemoryRegister$APU17) {
_inherits(APUFrameCounter, _InMemoryRegister$APU17);
var _super17 = _createSuper(APUFrameCounter);
function APUFrameCounter() {
_classCallCheck(this, APUFrameCounter);
return _super17.apply(this, arguments);
}
_createClass(APUFrameCounter, [{
key: "onLoad",
value: function onLoad() {
this.addField("use5StepSequencer", 7);
}
}, {
key: "onWrite",
value: function onWrite(value) {
this.setValue(value);
this.apu.frameSequencer.reset();
this.apu.onQuarterFrameClock();
this.apu.onHalfFrameClock();
}
}]);
return APUFrameCounter;
}(_InMemoryRegister.default.APU);
var AudioRegisters = /*#__PURE__*/function () {
function AudioRegisters(apu) {
_classCallCheck(this, AudioRegisters);
this.pulses = [0, 1].map(function (id) {
return {
control: new PulseControl(apu),
// $4000/$4004
sweep: new PulseSweep(apu, id),
// $4001/$4005
timerLow: new PulseTimerLow(apu, id),
// $4002/$4006
timerHighLCL: new PulseTimerHighLCL(apu, id) // $4003/$4007
};
});
this.triangle = {
lengthControl: new TriangleLengthControl(apu),
// $4008
timerLow: new TriangleTimerLow(apu),
// $400A
timerHighLCL: new TriangleTimerHighLCL(apu) // $400B
};
this.noise = {
control: new NoiseControl(apu),
// $400C
form: new NoiseForm(apu),
// $400E
lcl: new NoiseLCL(apu) // $400F
};
this.dmc = {
control: new DMCControl(apu),
// $4010
load: new DMCLoad(apu),
// $4011
sampleAddress: new DMCSampleAddress(apu),
// $4012
sampleLength: new DMCSampleLength(apu) // $4013
};
this.apuStatus = new APUStatus(apu); // $4015 (read)
this.apuControl = new APUControl(apu); // $4015 (write)
this.apuFrameCounter = new APUFrameCounter(apu); // $4017
}
_createClass(AudioRegisters, [{
key: "read",
value: function read(address) {
var _this$_getRegister;
if (address === 0x4015) return this.apuStatus.onRead();
return (_this$_getRegister = this._getRegister(address)) === null || _this$_getRegister === void 0 ? void 0 : _this$_getRegister.onRead();
}
}, {
key: "write",
value: function write(address, value) {
var _this$_getRegister2;
if (address === 0x4015) return this.apuControl.onWrite(value);
(_this$_getRegister2 = this._getRegister(address)) === null || _this$_getRegister2 === void 0 ? void 0 : _this$_getRegister2.onWrite(value);
}
}, {
key: "_getRegister",
value: function _getRegister(address) {
switch (address) {
case 0x4000:
return this.pulses[0].control;
case 0x4001:
return this.pulses[0].sweep;
case 0x4002:
return this.pulses[0].timerLow;
case 0x4003:
return this.pulses[0].timerHighLCL;
case 0x4004:
return this.pulses[1].control;
case 0x4005:
return this.pulses[1].sweep;
case 0x4006:
return this.pulses[1].timerLow;
case 0x4007:
return this.pulses[1].timerHighLCL;
case 0x4008:
return this.triangle.lengthControl;
case 0x400a:
return this.triangle.timerLow;
case 0x400b:
return this.triangle.timerHighLCL;
case 0x400c:
return this.noise.control;
case 0x400e:
return this.noise.form;
case 0x400f:
return this.noise.lcl;
case 0x4010:
return this.dmc.control;
case 0x4011:
return this.dmc.load;
case 0x4012:
return this.dmc.sampleAddress;
case 0x4013:
return this.dmc.sampleLength;
case 0x4017:
return this.apuFrameCounter;
default:
}
}
}]);
return AudioRegisters;
}();
exports.default = AudioRegisters;