UNPKG

furnace-module-interface

Version:

An interface for loading, processing and saving furnace modules in an object-oriented manner. Fully typed via TypeScript.

286 lines (285 loc) 18.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getEffectName = exports.getVersionString = exports.loadFurnaceModule = exports.inflateBuffer = exports.deflateBuffer = exports.FurnaceWavetableModule = exports.FurnaceSongModule = exports.FurnaceInstrumentModule = void 0; const instrumentModule_1 = require("./instrumentModule"); Object.defineProperty(exports, "FurnaceInstrumentModule", { enumerable: true, get: function () { return instrumentModule_1.FurnaceInstrumentModule; } }); const songModule_1 = require("./songModule"); Object.defineProperty(exports, "FurnaceSongModule", { enumerable: true, get: function () { return songModule_1.FurnaceSongModule; } }); const wavetableModule_1 = require("./wavetableModule"); Object.defineProperty(exports, "FurnaceWavetableModule", { enumerable: true, get: function () { return wavetableModule_1.FurnaceWavetableModule; } }); const zlib = __importStar(require("zlib")); const bufferHelper_1 = require("./bufferHelper"); __exportStar(require("./channels"), exports); __exportStar(require("./chips"), exports); __exportStar(require("./info"), exports); __exportStar(require("./instrument"), exports); __exportStar(require("./macros"), exports); __exportStar(require("./meta"), exports); __exportStar(require("./pattern"), exports); __exportStar(require("./sample"), exports); __exportStar(require("./song"), exports); __exportStar(require("./wavetable"), exports); const chips_1 = require("./chips"); function deflateBuffer(data) { return new Promise((res, rej) => { zlib.deflate(data, (error, result) => { if (error) { rej(error); } res(result); }); }); } exports.deflateBuffer = deflateBuffer; function inflateBuffer(data) { return new Promise((res, rej) => { zlib.inflate(data, (error, result) => { if (error) { rej(error); } res(result); }); }); } exports.inflateBuffer = inflateBuffer; function loadFurnaceModule(data, compressed) { return __awaiter(this, void 0, void 0, function* () { let realBuffer = data; if (compressed !== false) { let newBuffer; try { newBuffer = yield inflateBuffer(data); } catch (error) { if (compressed === true) { throw error; } } if (newBuffer) { realBuffer = newBuffer; } } const helper = new bufferHelper_1.BufferReadHelper(realBuffer); return loadModuleFromHelper(helper); }); } exports.loadFurnaceModule = loadFurnaceModule; function loadModuleFromHelper(helper) { const magic = helper.getASCII(16, 0); helper.setPosition(helper.getPosition(-16)); switch (magic) { case songModule_1.FurnaceSongModule.magic: return songModule_1.FurnaceSongModule.fromHelper(helper); case instrumentModule_1.FurnaceInstrumentModule.magic: return instrumentModule_1.FurnaceInstrumentModule.fromHelper(helper); case wavetableModule_1.FurnaceWavetableModule.magic: return wavetableModule_1.FurnaceWavetableModule.fromHelper(helper); } throw new Error("Unable to determine module type!"); } function getVersionString(version) { const name = versioNames[version]; if (name) { return name; } if (Math.round(version) === version && version >= 57 && version <= 99) { return "dev" + version; } return undefined; } exports.getVersionString = getVersionString; const versioNames = { 12: "0.2", 13: "0.2.1", 14: "0.2.2", 15: "0.3", 16: "0.3.1", 17: "0.4pre1", 18: "0.4pre2", 19: "0.4pre3", 20: "0.4", 21: "0.4.1", 22: "0.4.2", 23: "0.4.3", 24: "0.4.4", 25: "0.4.5", 26: "0.4.6pre1", 27: "0.4.6", 35: "0.5", 36: "0.5.1", 37: "0.5.2pre1", 38: "0.5.2pre2", 39: "0.5.2pre3", 40: "0.5.2", 41: "0.5.3", 42: "0.5.4", 43: "0.5.5pre1", 44: "0.5.5pre2", 45: "0.5.5pre3", 46: "0.5.5", 47: "0.5.6pre1", 48: "0.5.6", 49: "0.5.7pre1", 50: "0.5.7pre2", 51: "0.5.7pre3", 52: "0.5.7pre4", 53: "0.5.7", 54: "0.5.8", 75: "0.6pre0/April Fools", 100: "0.6pre1", 101: "0.6pre1", 102: "0.6pre1", }; function getEffectName(type, effect) { let name = globalEffectNames[effect]; if (name) { return name; } switch (type) { case chips_1.FurnaceSystemEnum.YM2612: case chips_1.FurnaceSystemEnum.YM2612Extended: name = effectsYM2612[effect]; break; case chips_1.FurnaceSystemEnum.Genesis: case chips_1.FurnaceSystemEnum.GenesisExtended: name = effectsYM2612[effect] || effectsSN76489[effect]; break; case chips_1.FurnaceSystemEnum.SMS: name = effectsSN76489[effect]; break; } if (name) { return name; } return { parameters: [], }; } exports.getEffectName = getEffectName; const globalEffectNames = { 0x90: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x91: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x92: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x93: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x94: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x95: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x96: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x97: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x98: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x99: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x9A: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x9B: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x9C: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x9D: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0x9F: { minversion: 12, format: "9xxx", name: "Sample offset", parameters: [{ xxx: "Sample offset = xxx*256", },], }, 0xC0: { minversion: 12, format: "Cxxx", name: "Set Tick Rate", parameters: [{ xxx: "Tick rate in hz = xxx. Minimum = 10, maximum = 3FF", },], }, 0xC1: { minversion: 12, format: "Cxxx", name: "Set Tick Rate", parameters: [{ xxx: "Tick rate in hz = xxx. Minimum = 10, maximum = 3FF", },], }, 0xC2: { minversion: 12, format: "Cxxx", name: "Set Tick Rate", parameters: [{ xxx: "Tick rate in hz = xxx. Minimum = 10, maximum = 3FF", },], }, 0xC3: { minversion: 12, format: "Cxxx", name: "Set Tick Rate", parameters: [{ xxx: "Tick rate in hz = xxx. Minimum = 10, maximum = 3FF", },], }, 0xF0: { minversion: 12, format: "F0xx", name: "Set Tick Rate", parameters: [{ xxx: "Tick rate in bpm = xx", },], }, 0x00: { minversion: 12, format: "00xy", name: "Arpeggio", parameters: [{ x: "Semitone offset 1", y: "Semitone offset 2", },], }, 0xE0: { minversion: 12, format: "E0xx", name: "Arpeggio Speed", parameters: [{ xx: "The number of ticks between arpeggio change", },], }, 0x01: { minversion: 12, format: "01xx", name: "Pitch Slide Up", parameters: [{ xx: "Speed of the slide", },], }, 0x02: { minversion: 12, format: "02xx", name: "Pitch Slide Down", parameters: [{ xx: "Speed of the slide", },], }, 0x03: { minversion: 12, format: "03xx", name: "Portamento", parameters: [{ xx: "Speed of the portamento", },], }, 0xE1: { minversion: 12, format: "E1xy", name: "Note Slide Up", parameters: [{ x: "Speed of the slide", y: "Number of semitones to slide", },], }, 0xE2: { minversion: 12, format: "E2xy", name: "Note Slide Down", parameters: [{ x: "Speed of the slide", y: "Number of semitones to slide", },], }, 0xF1: { minversion: 12, format: "F1xx", name: "Pitch Slide Up", explanation: "Single tick variant", parameters: [{ xx: "Speed of the slide", },], }, 0xF2: { minversion: 12, format: "F2xx", name: "Pitch Slide Down", explanation: "Single tick variant", parameters: [{ xx: "Speed of the slide", },], }, 0x0A: { minversion: 12, format: "0Axy", name: "Volume Slide", parameters: [{ x0: "slide up speed", "0y": "slide down speed", },], }, 0xFA: { minversion: 12, format: "FAxy", name: "Volume Slide", explanation: "4x faster variant", parameters: [{ x0: "slide up", "0y": "slide down", },], }, 0xF3: { minversion: 12, format: "F3xx", name: "Fine Volume Slide Up", parameters: [{ xx: "speed", },], }, 0xF4: { minversion: 12, format: "F4xx", name: "Fine Volume Slide Down", parameters: [{ xx: "speed", },], }, 0xF8: { minversion: 12, format: "F8xx", name: "Fine Volume Slide Up", explanation: "single tick variant", parameters: [{ xx: "speed", },], }, 0xF9: { minversion: 12, format: "F9xx", name: "Fine Volume Slide Down", explanation: "single tick variant", parameters: [{ xx: "speed", },], }, 0x04: { minversion: 12, format: "04xy", name: "Vibrato", parameters: [{ x: "speed", y: "depth", },], }, 0xE4: { minversion: 12, format: "E4xx", name: "Vibrato Range", parameters: [{ xx: "range in 1/16th of a semitone", },], }, 0xE3: { minversion: 12, format: "E3xx", name: "Vibrato Shape", parameters: [{ xx: "0 = sine up/down, 1 = sine up/0, 2 = sine 0/down", },], }, 0x07: { minversion: 12, format: "07xy", name: "Tremolo", parameters: [{ x: "speed", y: "depth", },], }, 0x08: { minversion: 12, format: "08xy", name: "Set Panning", parameters: [{ x: "left", y: "right", },], }, 0x80: { minversion: 12, format: "80xx", name: "Set Panning", parameters: [{ xx: "00 = left, 80 = center, FF = right", },], }, 0x81: { minversion: 12, format: "81xx", name: "Set Panning", explanation: "Left channel panning", parameters: [], }, 0x82: { minversion: 12, format: "82xx", name: "Set Panning", explanation: "Right channel panning", parameters: [], }, 0x09: { minversion: 12, format: "09xx", name: "Set Speed 1", parameters: [], }, 0x0F: { minversion: 12, format: "0Fxx", name: "Set Speed 2", parameters: [], }, 0x0B: { minversion: 12, format: "0Bxx", name: "Jump To Pattern", parameters: [], }, 0x0D: { minversion: 12, format: "0Dxx", name: "Jump To Next Pattern Row", parameters: [], }, 0xFF: { minversion: 12, format: "FFxx", name: "Stop Song", parameters: [], }, 0x0C: { minversion: 12, format: "0Cxx", name: "Retrigger", parameters: [], }, 0xEC: { minversion: 12, format: "ECxx", name: "Note Cut", parameters: [], }, 0xED: { minversion: 12, format: "EDxx", name: "Note Delay", parameters: [], }, 0xEA: { minversion: 12, format: "EAxx", name: "Legato", parameters: [{ xx: "0 = disabled", },], }, 0xE5: { minversion: 12, format: "E5xx", name: "Set Pitch", parameters: [{ xx: "80 = center, FF = ~1 semitone, 00 = ~-1 semitone", },], }, 0xEF: { minversion: 12, format: "EFxx", name: "Set Global Pitch", explanation: "Broken", parameters: [], }, 0xEB: { minversion: 12, format: "EBxx", name: "Set Sample Bank", parameters: [], }, 0xEE: { minversion: 12, format: "EExx", name: "External Command", parameters: [], }, }; const effectsYM2612 = { 0x17: { minversion: 12, format: "17xx", name: "Enable DAC", parameters: [{ xx: "00 = disabled", },], }, 0x18: { minversion: 12, format: "18xx", name: "Enable Extended CH3 mode", parameters: [{ xx: "00 = disabled", },], }, 0x10: { minversion: 12, format: "10xy", name: "Setup LFO", parameters: [{ x: "enable", y: "speed", },], }, 0x11: { minversion: 12, format: "11xx", name: "Set Feedback", parameters: [{ xx: "values 00 to 07 supported", },], }, 0x30: { minversion: 12, format: "30xx", name: "Toggle Hard Envelope Reset", parameters: [{ xx: "00 = disabled", },], }, 0x16: { minversion: 12, format: "16xy", name: "Set Multiple", parameters: [{ x: "values 0 to F supported", y: "operator from 1 to 4", },], }, 0x50: { minversion: 12, format: "50xy", name: "Set Amplitude Modulation", parameters: [{ x: "0 = disabled", y: "operator from 1 to 4, or 0 for all operators", },], }, 0x51: { minversion: 12, format: "51xy", name: "Set Sustain Level", parameters: [{ x: "values 0 to F supported", y: "operator from 1 to 4, or 0 for all operators", },], }, 0x52: { minversion: 12, format: "52xy", name: "Set Release Rate", parameters: [{ x: "values 0 to F supported", y: "operator from 1 to 4, or 0 for all operators", },], }, 0x53: { minversion: 12, format: "53xy", name: "Set Detune", parameters: [{ x: "values 0 to 7 supported, 3 = center", y: "operator from 1 to 4, or 0 for all operators", },], }, 0x54: { minversion: 12, format: "54xy", name: "Set Rate Scale", parameters: [{ x: "values 0 to 3 supported", y: "operator from 1 to 4, or 0 for all operators", },], }, 0x55: { minversion: 12, format: "55xy", name: "Set SSG-EG", parameters: [{ x: "values 0 to 7 = envelope enabled, 8 - F = envelope disabled", y: "operator from 1 to 4, or 0 for all operators", },], }, 0x12: { minversion: 12, format: "12xx", name: "Set Total Level Of Operator 1", parameters: [{ xx: "values 00 (highest) to 7F (lowest) supported", },], }, 0x13: { minversion: 12, format: "13xx", name: "Set Total Level Of Operator 2", parameters: [{ xx: "values 00 (highest) to 7F (lowest) supported", },], }, 0x14: { minversion: 12, format: "14xx", name: "Set Total Level Of Operator 3", parameters: [{ xx: "values 00 (highest) to 7F (lowest) supported", },], }, 0x15: { minversion: 12, format: "15xx", name: "Set Total Level Of Operator 4", parameters: [{ xx: "values 00 (highest) to 7F (lowest) supported", },], }, 0x19: { minversion: 12, format: "19xx", name: "Set Attack Rate All Operators", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x1A: { minversion: 12, format: "1Axx", name: "Set Attack Rate Of Operator 1", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x1B: { minversion: 12, format: "1Bxx", name: "Set Attack Rate Of Operator 2", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x1C: { minversion: 12, format: "1Cxx", name: "Set Attack Rate Of Operator 3", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x1D: { minversion: 12, format: "1Dxx", name: "Set Attack Rate Of Operator 4", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x56: { minversion: 12, format: "56xx", name: "Set Decay 1 Rate All Operators", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x57: { minversion: 12, format: "57xx", name: "Set Decay 1 Rate Of Operator 1", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x58: { minversion: 12, format: "58xx", name: "Set Decay 1 Rate Of Operator 2", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x59: { minversion: 12, format: "59xx", name: "Set Decay 1 Rate Of Operator 3", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x5A: { minversion: 12, format: "5Axx", name: "Set Decay 1 Rate Of Operator 4", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x5B: { minversion: 12, format: "5Bxx", name: "Set Decay 2 Rate All Operators", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x5C: { minversion: 12, format: "5Cxx", name: "Set Decay 2 Rate Of Operator 1", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x5D: { minversion: 12, format: "5Dxx", name: "Set Decay 2 Rate Of Operator 2", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x5E: { minversion: 12, format: "5Exx", name: "Set Decay 2 Rate Of Operator 3", parameters: [{ xx: "values 00 to 1F supported", },], }, 0x5F: { minversion: 12, format: "5Fxx", name: "Set Decay 2 Rate Of Operator 4", parameters: [{ xx: "values 00 to 1F supported", },], }, }; const effectsSN76489 = { 0x20: { minversion: 12, format: "20xy", name: "Set Noise Mode", parameters: [{ x: "0 = preset freq, 1 = ch3 freq", y: "0 = periodic, 1 = white noise", },], }, };