UNPKG

broken-neees

Version:

A really broken NEEES emulator that introduces glitches and random bugs on purpose!

482 lines (477 loc) 19.5 kB
"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;