@logue/smfplayer
Version:
smfplayer.js is JavaScript based Standard Midi Player for WebMidiLink based synthesizer.
792 lines (610 loc) • 25.8 kB
JavaScript
/*! @logue/smfplayer v0.3.6 | imaya / GREE Inc. / Logue | license: MIT | build: 2021-11-04T14:33:02.374Z */
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("SMF", [], factory);
else if(typeof exports === 'object')
exports["SMF"] = factory();
else
root["SMF"] = factory();
})((typeof self !== 'undefined' ? self : this), function() {
return /******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/meta.js":
/*!*********************!*\
!*** ./src/meta.js ***!
\*********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
// This file is auto-generated by the build system.
var Meta = {
version: '0.3.6',
date: '2021-11-04T11:03:20.907Z'
};
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Meta);
/***/ }),
/***/ "./src/midi_event.js":
/*!***************************!*\
!*** ./src/midi_event.js ***!
\***************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "ChannelEvent": () => (/* binding */ ChannelEvent),
/* harmony export */ "SystemExclusiveEvent": () => (/* binding */ SystemExclusiveEvent),
/* harmony export */ "MetaEvent": () => (/* binding */ MetaEvent)
/* harmony export */ });
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
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 } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || 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 : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Midi Event abstract Structure
*/
var Event =
/**
* @param {string} subtype event subtype name.
* @param {number} deltaTime delta time.
* @param {number} time time.
*/
function Event(subtype, deltaTime, time) {
_classCallCheck(this, Event);
/** @type {string} */
this.subtype = subtype;
/** @type {number} */
this.deltaTime = deltaTime;
/** @type {number} */
this.time = time;
};
/**
* Midi Channel Event Structure
* @extends {Event}
*/
var ChannelEvent = /*#__PURE__*/function (_Event) {
_inherits(ChannelEvent, _Event);
var _super = _createSuper(ChannelEvent);
/**
* @param {string} subtype
* @param {number} deltaTime delta time.
* @param {number} time time.
* @param {number} channel
* @param {number=} optParameter1
* @param {number=} optParameter2
*/
function ChannelEvent(subtype, deltaTime, time, channel, optParameter1, optParameter2) {
var _this;
_classCallCheck(this, ChannelEvent);
_this = _super.call(this, subtype, deltaTime, time);
/** @type {number} */
_this.channel = channel;
/** @type {(number|undefined)} */
_this.parameter1 = optParameter1;
/** @type {(number|undefined)} */
_this.parameter2 = optParameter2;
return _this;
}
return ChannelEvent;
}(Event);
/**
* System Exclusive Event Structure
* @extends {Event}
*/
var SystemExclusiveEvent = /*#__PURE__*/function (_Event2) {
_inherits(SystemExclusiveEvent, _Event2);
var _super2 = _createSuper(SystemExclusiveEvent);
/**
* @param {string} subtype
* @param {number} deltaTime delta time.
* @param {number} time time.
* @param {ByteArray} data
*/
function SystemExclusiveEvent(subtype, deltaTime, time, data) {
var _this2;
_classCallCheck(this, SystemExclusiveEvent);
_this2 = _super2.call(this, subtype, deltaTime, time);
/** @type {ByteArray} */
_this2.data = data;
return _this2;
}
return SystemExclusiveEvent;
}(Event);
/**
* Midi Meta Event Structure
* @extends {Event}
*/
var MetaEvent = /*#__PURE__*/function (_Event3) {
_inherits(MetaEvent, _Event3);
var _super3 = _createSuper(MetaEvent);
/**
* @param {string} subtype
* @param {number} deltaTime delta time.
* @param {number} time time.
* @param {Array.<*>} data meta data.
*/
function MetaEvent(subtype, deltaTime, time, data) {
var _this3;
_classCallCheck(this, MetaEvent);
_this3 = _super3.call(this, subtype, deltaTime, time);
/** @type {Array.<*>} */
_this3.data = data;
return _this3;
}
return MetaEvent;
}(Event);
/***/ }),
/***/ "./src/riff.js":
/*!*********************!*\
!*** ./src/riff.js ***!
\*********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ Riff)
/* harmony export */ });
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, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/**
* Riff Parser class
*/
var Riff = /*#__PURE__*/function () {
/**
* @param {ByteArray} input input buffer.
* @param {Object=} optParams option parameters.
*/
function Riff(input) {
var optParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, Riff);
/** @type {ByteArray} */
this.input = input;
/** @type {number} */
this.ip = optParams.index || 0;
/** @type {number} */
this.length = optParams.length || input.length - this.ip;
/** @type {Array.<RiffChunk>} */
this.chunkList = [];
/** @type {number} */
this.offset = this.ip;
/** @type {boolean} */
this.padding = optParams.padding !== void 0 ? optParams.padding : true;
/** @type {boolean} */
this.bigEndian = optParams.bigEndian !== void 0 ? optParams.bigEndian : false;
}
/**
*/
_createClass(Riff, [{
key: "parse",
value: function parse() {
/** @type {number} */
var length = this.length + this.offset;
this.chunkList = [];
while (this.ip < length) {
this.parseChunk();
}
}
/**
*/
}, {
key: "parseChunk",
value: function parseChunk() {
/** @type {ByteArray} */
var input = this.input;
/** @type {number} */
var ip = this.ip;
/** @type {number} */
var size;
this.chunkList.push(new RiffChunk(String.fromCharCode(input[ip++], input[ip++], input[ip++], input[ip++]), size = this.bigEndian ? (input[ip++] << 24 | input[ip++] << 16 | input[ip++] << 8 | input[ip++]) >>> 0 : (input[ip++] | input[ip++] << 8 | input[ip++] << 16 | input[ip++] << 24) >>> 0, ip));
ip += size; // padding
if (this.padding && (ip - this.offset & 1) === 1) {
ip++;
}
this.ip = ip;
}
/**
* @param {number} index chunk index.
* @return {?RiffChunk}
*/
}, {
key: "getChunk",
value: function getChunk(index) {
/** @type {RiffChunk} */
var chunk = this.chunkList[index];
if (chunk === void 0) {
return null;
}
return chunk;
}
/**
* @return {number}
*/
}, {
key: "getNumberOfChunks",
value: function getNumberOfChunks() {
return this.chunkList.length;
}
}]);
return Riff;
}();
/**
* Riff Chunk Structure
* @interface
*/
var RiffChunk =
/**
* @param {string} type
* @param {number} size
* @param {number} offset
*/
function RiffChunk(type, size, offset) {
_classCallCheck(this, RiffChunk);
/** @type {string} */
this.type = type;
/** @type {number} */
this.size = size;
/** @type {number} */
this.offset = offset;
};
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
/*!********************!*\
!*** ./src/smf.js ***!
\********************/
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ SMF)
/* harmony export */ });
/* harmony import */ var _midi_event__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./midi_event */ "./src/midi_event.js");
/* harmony import */ var _meta__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./meta */ "./src/meta.js");
/* harmony import */ var _riff__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./riff */ "./src/riff.js");
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, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/**
* Standard Midi File Parser class
*/
var SMF = /*#__PURE__*/function () {
/**
* @param {ByteArray} input input buffer.
* @param {Object=} optParams option parameters.
*/
function SMF(input) {
var optParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, SMF);
optParams.padding = false;
optParams.bigEndian = true;
/** @type {ByteArray} */
this.input = input;
/** @type {number} */
this.ip = optParams.index || 0;
/** @type {number} */
this.chunkIndex = 0;
/**
* @type {Riff}
* @private
*/
this.riffParser_ = new _riff__WEBPACK_IMPORTED_MODULE_2__["default"](input, optParams); // MIDI File Information
/** @type {number} */
this.formatType = 0;
/** @type {number} */
this.numberOfTracks = 0;
/** @type {number} */
this.timeDivision = 480;
/** @type {Array.<Array.<Midi.Event>>} */
this.tracks = [];
/** @type {Array.<Array.<ByteArray>>} */
this.plainTracks = [];
/** @type {number} */
this.version = _meta__WEBPACK_IMPORTED_MODULE_1__["default"].version;
/** @type {string} */
this.build = _meta__WEBPACK_IMPORTED_MODULE_1__["default"].build;
}
/**
*/
_createClass(SMF, [{
key: "parse",
value: function parse() {
/** @type {number} */
var i = 0;
/** @type {number} */
var il = 0; // parse riff chunks
this.riffParser_.parse(); // parse header chunk
this.parseHeaderChunk(); // parse track chunks
for (i = 0, il = this.numberOfTracks; i < il; ++i) {
this.parseTrackChunk();
}
}
/**
*/
}, {
key: "parseHeaderChunk",
value: function parseHeaderChunk() {
/** @type {?{type: string, size: number, offset: number}} */
var chunk = this.riffParser_.getChunk(this.chunkIndex++);
/** @type {ByteArray} */
var data = this.input;
/** @type {number} */
var ip = chunk.offset;
if (!chunk || chunk.type !== 'MThd') {
throw new Error('invalid header signature');
}
this.formatType = data[ip++] << 8 | data[ip++];
this.numberOfTracks = data[ip++] << 8 | data[ip++];
this.timeDivision = data[ip++] << 8 | data[ip++];
}
/**
*/
}, {
key: "parseTrackChunk",
value: function parseTrackChunk() {
/** @type {?{type: string, size: number, offset: number}} */
var chunk = this.riffParser_.getChunk(this.chunkIndex++);
/** @type {ByteArray} */
var data = this.input;
/** @type {number} */
var ip = chunk.offset;
/** @type {number} */
var size = 0;
/** @type {number} */
var deltaTime = 0;
/** @type {number} */
var eventType = 0;
/** @type {number} */
var channel = 0;
/** @type {number} */
var prevEventType = -1;
/** @type {number} */
var prevChannel = -1;
/** @type {number} */
var tmp = 0;
/** @type {number} */
var totalTime = 0;
/** @type {number} */
var offset = 0;
/** @type {number} */
var length = 0;
/** @type {number} */
var status = 0;
/** @type {Event} */
var event;
/** @type {ByteArray} */
var plainBytes;
/** @return {number} */
var readNumber = function readNumber() {
/** @type {number} */
var result = 0;
tmp = 0;
do {
tmp = data[ip++];
result = result << 7 | tmp & 0x7f;
} while ((tmp & 0x80) !== 0);
return result;
};
if (!chunk || chunk.type !== 'MTrk') {
throw new Error('invalid header signature');
}
size = chunk.offset + chunk.size;
var eventQueue = [];
var plainQueue = [];
while (ip < size) {
// delta time
deltaTime = readNumber();
totalTime += deltaTime; // offset
offset = ip; // event type value, midi channel
status = data[ip++];
eventType = status >> 4 & 0xf;
channel = status & 0xf; // run status rule
if (eventType < 8) {
eventType = prevEventType;
channel = prevChannel;
status = prevEventType << 4 | prevChannel;
ip--;
offset--;
} else {
prevEventType = eventType;
prevChannel = channel;
} // TODO
var table = [null, null, null, null, null, null, null, null, 'NoteOff', // 0x8
'NoteOn', 'NoteAftertouch', 'ControlChange', 'ProgramChange', 'ChannelAftertouch', 'PitchBend'];
switch (eventType) {
// channel events
case 0x8:
/* FALLTHROUGH */
case 0x9:
/* FALLTHROUGH */
case 0xa:
/* FALLTHROUGH */
case 0xb:
/* FALLTHROUGH */
case 0xd:
/* FALLTHROUGH */
case 0xe:
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.ChannelEvent(table[eventType], deltaTime, totalTime, channel, data[ip++], data[ip++]);
break;
case 0xc:
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.ChannelEvent(table[eventType], deltaTime, totalTime, channel, data[ip++]);
break;
// meta events, system exclusive event
case 0xf:
switch (channel) {
// SysEx event
case 0x0:
tmp = readNumber();
if (data[ip + tmp - 1] !== 0xf7) {
throw new Error('invalid SysEx event');
}
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.SystemExclusiveEvent('SystemExclusive', deltaTime, totalTime, data.subarray(ip, (ip += tmp) - 1));
break;
case 0x7:
tmp = readNumber();
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.SystemExclusiveEvent('SystemExclusive(F7)', deltaTime, totalTime, data.subarray(ip, ip += tmp));
break;
// meta event
case 0xf:
eventType = data[ip++];
tmp = readNumber();
switch (eventType) {
case 0x00:
// sequence number
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('SequenceNumber', deltaTime, totalTime, [data[ip++], data[ip++]]);
break;
case 0x01:
// text event
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('TextEvent', deltaTime, totalTime, [String.fromCharCode.apply(null, data.subarray(ip, ip += tmp))]);
break;
case 0x02:
// copyright notice
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('CopyrightNotice', deltaTime, totalTime, [String.fromCharCode.apply(null, data.subarray(ip, ip += tmp))]);
break;
case 0x03:
// sequence/track name
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('SequenceTrackName', deltaTime, totalTime, [String.fromCharCode.apply(null, data.subarray(ip, ip += tmp))]);
break;
case 0x04:
// instrument name
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('InstrumentName', deltaTime, totalTime, [String.fromCharCode.apply(null, data.subarray(ip, ip += tmp))]);
break;
case 0x05:
// lyrics
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('Lyrics', deltaTime, totalTime, [String.fromCharCode.apply(null, data.subarray(ip, ip += tmp))]);
break;
case 0x06:
// marker
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('Marker', deltaTime, totalTime, [String.fromCharCode.apply(null, data.subarray(ip, ip += tmp))]);
break;
case 0x07:
// cue point
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('CuePoint', deltaTime, totalTime, [String.fromCharCode.apply(null, data.subarray(ip, ip += tmp))]);
break;
case 0x20:
// midi channel prefix
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('MidiChannelPrefix', deltaTime, totalTime, [data[ip++]]);
break;
case 0x2f:
// end of track
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('EndOfTrack', deltaTime, totalTime, []);
break;
case 0x51:
// set tempo
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('SetTempo', deltaTime, totalTime, [data[ip++] << 16 | data[ip++] << 8 | data[ip++]]);
break;
case 0x54:
// smpte offset
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('SmpteOffset', deltaTime, totalTime, [data[ip++], data[ip++], data[ip++], data[ip++], data[ip++]]);
break;
case 0x58:
// time signature
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('TimeSignature', deltaTime, totalTime, [data[ip++], data[ip++], data[ip++], data[ip++]]);
break;
case 0x59:
// key signature
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('KeySignature', deltaTime, totalTime, [data[ip++], data[ip++]]);
break;
case 0x7f:
// sequencer specific
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('SequencerSpecific', deltaTime, totalTime, [data.subarray(ip, ip += tmp)]);
break;
default:
// unknown
event = new _midi_event__WEBPACK_IMPORTED_MODULE_0__.MetaEvent('Unknown', deltaTime, totalTime, [eventType, data.subarray(ip, ip += tmp)]);
}
break;
default:
console.warn('unknown message:', status.toString(16));
}
break;
// error
default:
throw new Error('invalid status');
} // plain queue
length = ip - offset;
plainBytes = data.subarray(offset, offset + length);
plainBytes[0] = status;
if (event instanceof _midi_event__WEBPACK_IMPORTED_MODULE_0__.ChannelEvent && event.subtype === 'NoteOn' &&
/** @type {ChannelEvent} */
event.parameter2 === 0) {
event.subtype = table[8];
plainBytes = new Uint8Array([0x80 | event.channel, event.parameter1, event.parameter2]);
}
plainQueue.push(plainBytes); // event queue
eventQueue.push(event);
}
this.tracks.push(eventQueue);
this.plainTracks.push(plainQueue);
}
}]);
return SMF;
}();
})();
/******/ return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=smf.parser.js.map