From 637f80597c52c6c9c81cc4e54ea1a3eb9d1339a8 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Sun, 26 Apr 2020 17:51:57 -0600 Subject: [PATCH 1/6] push WIP typescript port before idk my computer crashes or something --- dist/playback.cjs | 3956 ++++++++ dist/playback.node.mjs | 3930 ++++++++ dist/playback.web.mjs | 3930 ++++++++ package-lock.json | 8456 +++-------------- package.json | 30 +- playground/index.html | 28 + rollup.config.js | 60 + src/MIDI/{Note.js => Note.ts} | 31 +- .../{PlaybackStyle.js => PlaybackStyle.ts} | 41 +- src/Player/{Player.js => Player.ts} | 26 +- ...umentOperators.js => ArgumentOperators.ts} | 38 +- src/ast/{BeatGroups.js => BeatGroups.ts} | 42 +- src/ast/{BeatLiterals.js => BeatLiterals.ts} | 39 +- ...onfigStatements.js => ConfigStatements.ts} | 37 +- src/ast/{FunctionCall.js => FunctionCall.ts} | 34 +- src/ast/{GlobalScope.js => GlobalScope.ts} | 35 +- src/ast/{Pattern.js => Pattern.ts} | 43 +- src/ast/{Scope.js => Scope.ts} | 6 + src/ast/{Track.js => Track.ts} | 34 +- src/ast/{ast_nodes.js => ast_nodes.ts} | 0 src/ast/{errors.js => errors.ts} | 4 +- .../{function_data.js => function_data.ts} | 17 +- src/ast/{type_utils.js => type_utils.ts} | 0 src/lexer/{lexer.js => lexer.ts} | 0 src/loader/loader-node.js | 37 - src/loader/loader.js | 28 - src/loader/loader.ts | 57 + src/parser/grammar.ne | 4 +- src/parser/{parser.js => parser.ts} | 42 +- src/parser/test/styles/ambig.play | 18 - src/parser/test/styles/example.play | 96 - src/parser/test/test.js | 32 - src/{index.js => playback.ts} | 4 +- test/index.html | 66 - test/parser.ts | 73 + test/test.bundle.js | 494 - test/test.js | 26 - test/test.ts | 15 + test/tsconfig.json | 8 + tsconfig.json | 12 + types/MIDI/Note.d.ts | 32 + types/PlaybackStyle/PlaybackStyle.d.ts | 32 + types/Player/Player.d.ts | 15 + types/ast/ArgumentOperators.d.ts | 28 + types/ast/BeatGroups.d.ts | 34 + types/ast/BeatLiterals.d.ts | 61 + types/ast/ConfigStatements.d.ts | 18 + types/ast/FunctionCall.d.ts | 29 + types/ast/GlobalScope.d.ts | 21 + types/ast/Pattern.d.ts | 44 + types/ast/Scope.d.ts | 10 + types/ast/Track.d.ts | 23 + types/ast/ast_nodes.d.ts | 16 + types/ast/errors.d.ts | 34 + types/ast/function_data.d.ts | 25 + types/ast/type_utils.d.ts | 3 + types/loader/loader.d.ts | 14 + types/parser/parser.d.ts | 20 + types/playback.d.ts | 2 + webpack.config.js | 51 - 60 files changed, 14155 insertions(+), 8186 deletions(-) create mode 100644 dist/playback.cjs create mode 100644 dist/playback.node.mjs create mode 100644 dist/playback.web.mjs create mode 100644 playground/index.html create mode 100644 rollup.config.js rename src/MIDI/{Note.js => Note.ts} (76%) rename src/PlaybackStyle/{PlaybackStyle.js => PlaybackStyle.ts} (75%) rename src/Player/{Player.js => Player.ts} (80%) rename src/ast/{ArgumentOperators.js => ArgumentOperators.ts} (62%) rename src/ast/{BeatGroups.js => BeatGroups.ts} (76%) rename src/ast/{BeatLiterals.js => BeatLiterals.ts} (86%) rename src/ast/{ConfigStatements.js => ConfigStatements.ts} (50%) rename src/ast/{FunctionCall.js => FunctionCall.ts} (62%) rename src/ast/{GlobalScope.js => GlobalScope.ts} (71%) rename src/ast/{Pattern.js => Pattern.ts} (82%) rename src/ast/{Scope.js => Scope.ts} (81%) rename src/ast/{Track.js => Track.ts} (77%) rename src/ast/{ast_nodes.js => ast_nodes.ts} (100%) rename src/ast/{errors.js => errors.ts} (96%) rename src/ast/{function_data.js => function_data.ts} (96%) rename src/ast/{type_utils.js => type_utils.ts} (100%) rename src/lexer/{lexer.js => lexer.ts} (100%) delete mode 100644 src/loader/loader-node.js delete mode 100644 src/loader/loader.js create mode 100644 src/loader/loader.ts rename src/parser/{parser.js => parser.ts} (57%) delete mode 100644 src/parser/test/styles/ambig.play delete mode 100644 src/parser/test/styles/example.play delete mode 100644 src/parser/test/test.js rename src/{index.js => playback.ts} (68%) delete mode 100644 test/index.html create mode 100644 test/parser.ts delete mode 100644 test/test.bundle.js delete mode 100644 test/test.js create mode 100644 test/test.ts create mode 100644 test/tsconfig.json create mode 100644 tsconfig.json create mode 100644 types/MIDI/Note.d.ts create mode 100644 types/PlaybackStyle/PlaybackStyle.d.ts create mode 100644 types/Player/Player.d.ts create mode 100644 types/ast/ArgumentOperators.d.ts create mode 100644 types/ast/BeatGroups.d.ts create mode 100644 types/ast/BeatLiterals.d.ts create mode 100644 types/ast/ConfigStatements.d.ts create mode 100644 types/ast/FunctionCall.d.ts create mode 100644 types/ast/GlobalScope.d.ts create mode 100644 types/ast/Pattern.d.ts create mode 100644 types/ast/Scope.d.ts create mode 100644 types/ast/Track.d.ts create mode 100644 types/ast/ast_nodes.d.ts create mode 100644 types/ast/errors.d.ts create mode 100644 types/ast/function_data.d.ts create mode 100644 types/ast/type_utils.d.ts create mode 100644 types/loader/loader.d.ts create mode 100644 types/parser/parser.d.ts create mode 100644 types/playback.d.ts delete mode 100644 webpack.config.js diff --git a/dist/playback.cjs b/dist/playback.cjs new file mode 100644 index 0000000..b504240 --- /dev/null +++ b/dist/playback.cjs @@ -0,0 +1,3956 @@ +/** + * playback by Jacob Bloom + * This software is provided as-is, yadda yadda yadda + */ + +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } + +function _interopNamespace(e) { + if (e && e.__esModule) { return e; } else { + var n = {}; + if (e) { + Object.keys(e).forEach(function (k) { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { + return e[k]; + } + }); + }); + } + n['default'] = e; + return n; + } +} + +var _Tonal = require('tonal'); +var _Tonal__default = _interopDefault(_Tonal); + +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + +function __awaiter(thisArg, _arguments, P, generator) { + 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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +/** + * Load a file. + * + * * Style locator algorithm: + * 1. If the path begins with http:// or https://, look at that URL + * 2. If the path begins with . or / look in the filesystem or at a relative URL + * 3. Otherwise, look in the styles folder in this repo (which will move to its + * own repo eventually). For these built-in styles, the .play file extension + * is not required. + * + * @param {string} path The path to the file to load. + * @return {string} The content of the file. + */ +function load(stylePath) { + return __awaiter(this, void 0, void 0, function* () { + let isHTTP = stylePath.startsWith('http://') || stylePath.startsWith('https://'); + let isRelative = stylePath.startsWith('.') || stylePath.startsWith('/'); + if (typeof process === 'undefined') { + if (isHTTP || isRelative) { + return fetch(stylePath).then(r => r.text()); + } + else { + let modulePath = ''; //String(import.meta.url).replace(/[^\/]+$/, ''); + stylePath = modulePath + '../../styles/' + stylePath; + if (!stylePath.endsWith('.play')) + stylePath += '.play'; + return fetch(stylePath).then(r => r.text()); + } + } + else { + if (isHTTP) { + const http = yield new Promise(function (resolve) { resolve(_interopNamespace(require(stylePath.startsWith('https://') ? 'https' : 'http'))); }); + return new Promise((resolve, reject) => { + http.get(stylePath, res => { + let body = ''; + res.setEncoding('utf8'); + res.on('data', data => body += data); + res.on('end', () => resolve(body)); + res.on('error', reject); + }); + }); + } + if (!isRelative) { + let path = yield new Promise(function (resolve) { resolve(_interopNamespace(require('path'))); }); + try { + stylePath = path.join(__dirname, '../../styles/', stylePath); + } + catch (_a) { } + if (!stylePath.endsWith('.play')) + stylePath += '.play'; + } + let fs = yield new Promise(function (resolve) { resolve(_interopNamespace(require('fs'))); }); + return (new Promise((resolve, reject) => { + fs.readFile(stylePath, 'utf8', (err, data) => { + if (err) { + reject(err); + } + else { + resolve(data); + } + }); + })); + } + }); +} + +var nearley = (function() { + + function Rule(name, symbols, postprocess) { + this.id = ++Rule.highestId; + this.name = name; + this.symbols = symbols; // a list of literal | regex class | nonterminal + this.postprocess = postprocess; + return this; + } + Rule.highestId = 0; + + Rule.prototype.toString = function(withCursorAt) { + function stringifySymbolSequence (e) { + return e.literal ? JSON.stringify(e.literal) : + e.type ? '%' + e.type : e.toString(); + } + var symbolSequence = (typeof withCursorAt === "undefined") + ? this.symbols.map(stringifySymbolSequence).join(' ') + : ( this.symbols.slice(0, withCursorAt).map(stringifySymbolSequence).join(' ') + + " ● " + + this.symbols.slice(withCursorAt).map(stringifySymbolSequence).join(' ') ); + return this.name + " → " + symbolSequence; + }; + + + // a State is a rule at a position from a given starting point in the input stream (reference) + function State(rule, dot, reference, wantedBy) { + this.rule = rule; + this.dot = dot; + this.reference = reference; + this.data = []; + this.wantedBy = wantedBy; + this.isComplete = this.dot === rule.symbols.length; + } + + State.prototype.toString = function() { + return "{" + this.rule.toString(this.dot) + "}, from: " + (this.reference || 0); + }; + + State.prototype.nextState = function(child) { + var state = new State(this.rule, this.dot + 1, this.reference, this.wantedBy); + state.left = this; + state.right = child; + if (state.isComplete) { + state.data = state.build(); + } + return state; + }; + + State.prototype.build = function() { + var children = []; + var node = this; + do { + children.push(node.right.data); + node = node.left; + } while (node.left); + children.reverse(); + return children; + }; + + State.prototype.finish = function() { + if (this.rule.postprocess) { + this.data = this.rule.postprocess(this.data, this.reference, Parser.fail); + } + }; + + + function Column(grammar, index) { + this.grammar = grammar; + this.index = index; + this.states = []; + this.wants = {}; // states indexed by the non-terminal they expect + this.scannable = []; // list of states that expect a token + this.completed = {}; // states that are nullable + } + + + Column.prototype.process = function(nextColumn) { + var states = this.states; + var wants = this.wants; + var completed = this.completed; + + for (var w = 0; w < states.length; w++) { // nb. we push() during iteration + var state = states[w]; + + if (state.isComplete) { + state.finish(); + if (state.data !== Parser.fail) { + // complete + var wantedBy = state.wantedBy; + for (var i = wantedBy.length; i--; ) { // this line is hot + var left = wantedBy[i]; + this.complete(left, state); + } + + // special-case nullables + if (state.reference === this.index) { + // make sure future predictors of this rule get completed. + var exp = state.rule.name; + (this.completed[exp] = this.completed[exp] || []).push(state); + } + } + + } else { + // queue scannable states + var exp = state.rule.symbols[state.dot]; + if (typeof exp !== 'string') { + this.scannable.push(state); + continue; + } + + // predict + if (wants[exp]) { + wants[exp].push(state); + + if (completed.hasOwnProperty(exp)) { + var nulls = completed[exp]; + for (var i = 0; i < nulls.length; i++) { + var right = nulls[i]; + this.complete(state, right); + } + } + } else { + wants[exp] = [state]; + this.predict(exp); + } + } + } + }; + + Column.prototype.predict = function(exp) { + var rules = this.grammar.byName[exp] || []; + + for (var i = 0; i < rules.length; i++) { + var r = rules[i]; + var wantedBy = this.wants[exp]; + var s = new State(r, 0, this.index, wantedBy); + this.states.push(s); + } + }; + + Column.prototype.complete = function(left, right) { + var copy = left.nextState(right); + this.states.push(copy); + }; + + + function Grammar(rules, start) { + this.rules = rules; + this.start = start || this.rules[0].name; + var byName = this.byName = {}; + this.rules.forEach(function(rule) { + if (!byName.hasOwnProperty(rule.name)) { + byName[rule.name] = []; + } + byName[rule.name].push(rule); + }); + } + + // So we can allow passing (rules, start) directly to Parser for backwards compatibility + Grammar.fromCompiled = function(rules, start) { + var lexer = rules.Lexer; + if (rules.ParserStart) { + start = rules.ParserStart; + rules = rules.ParserRules; + } + var rules = rules.map(function (r) { return (new Rule(r.name, r.symbols, r.postprocess)); }); + var g = new Grammar(rules, start); + g.lexer = lexer; // nb. storing lexer on Grammar is iffy, but unavoidable + return g; + }; + + + function StreamLexer() { + this.reset(""); + } + + StreamLexer.prototype.reset = function(data, state) { + this.buffer = data; + this.index = 0; + this.line = state ? state.line : 1; + this.lastLineBreak = state ? -state.col : 0; + }; + + StreamLexer.prototype.next = function() { + if (this.index < this.buffer.length) { + var ch = this.buffer[this.index++]; + if (ch === '\n') { + this.line += 1; + this.lastLineBreak = this.index; + } + return {value: ch}; + } + }; + + StreamLexer.prototype.save = function() { + return { + line: this.line, + col: this.index - this.lastLineBreak, + } + }; + + StreamLexer.prototype.formatError = function(token, message) { + // nb. this gets called after consuming the offending token, + // so the culprit is index-1 + var buffer = this.buffer; + if (typeof buffer === 'string') { + var nextLineBreak = buffer.indexOf('\n', this.index); + if (nextLineBreak === -1) nextLineBreak = buffer.length; + var line = buffer.substring(this.lastLineBreak, nextLineBreak); + var col = this.index - this.lastLineBreak; + message += " at line " + this.line + " col " + col + ":\n\n"; + message += " " + line + "\n"; + message += " " + Array(col).join(" ") + "^"; + return message; + } else { + return message + " at index " + (this.index - 1); + } + }; + + + function Parser(rules, start, options) { + if (rules instanceof Grammar) { + var grammar = rules; + var options = start; + } else { + var grammar = Grammar.fromCompiled(rules, start); + } + this.grammar = grammar; + + // Read options + this.options = { + keepHistory: false, + lexer: grammar.lexer || new StreamLexer, + }; + for (var key in (options || {})) { + this.options[key] = options[key]; + } + + // Setup lexer + this.lexer = this.options.lexer; + this.lexerState = undefined; + + // Setup a table + var column = new Column(grammar, 0); + var table = this.table = [column]; + + // I could be expecting anything. + column.wants[grammar.start] = []; + column.predict(grammar.start); + // TODO what if start rule is nullable? + column.process(); + this.current = 0; // token index + } + + // create a reserved token for indicating a parse fail + Parser.fail = {}; + + Parser.prototype.feed = function(chunk) { + var lexer = this.lexer; + lexer.reset(chunk, this.lexerState); + + var token; + while (token = lexer.next()) { + // We add new states to table[current+1] + var column = this.table[this.current]; + + // GC unused states + if (!this.options.keepHistory) { + delete this.table[this.current - 1]; + } + + var n = this.current + 1; + var nextColumn = new Column(this.grammar, n); + this.table.push(nextColumn); + + // Advance all tokens that expect the symbol + var literal = token.value; + var value = lexer.constructor === StreamLexer ? token.value : token; + var scannable = column.scannable; + for (var w = scannable.length; w--; ) { + var state = scannable[w]; + var expect = state.rule.symbols[state.dot]; + // Try to consume the token + // either regex or literal + if (expect.test ? expect.test(value) : + expect.type ? expect.type === token.type + : expect.literal === literal) { + // Add it + var next = state.nextState({data: value, token: token, isToken: true, reference: n - 1}); + nextColumn.states.push(next); + } + } + + // Next, for each of the rules, we either + // (a) complete it, and try to see if the reference row expected that + // rule + // (b) predict the next nonterminal it expects by adding that + // nonterminal's start state + // To prevent duplication, we also keep track of rules we have already + // added + + nextColumn.process(); + + // If needed, throw an error: + if (nextColumn.states.length === 0) { + // No states at all! This is not good. + var message = this.lexer.formatError(token, "invalid syntax") + "\n"; + message += "Unexpected " + (token.type ? token.type + " token: " : ""); + message += JSON.stringify(token.value !== undefined ? token.value : token) + "\n"; + var err = new Error(message); + err.offset = this.current; + err.token = token; + throw err; + } + + // maybe save lexer state + if (this.options.keepHistory) { + column.lexerState = lexer.save(); + } + + this.current++; + } + if (column) { + this.lexerState = lexer.save(); + } + + // Incrementally keep track of results + this.results = this.finish(); + + // Allow chaining, for whatever it's worth + return this; + }; + + Parser.prototype.save = function() { + var column = this.table[this.current]; + column.lexerState = this.lexerState; + return column; + }; + + Parser.prototype.restore = function(column) { + var index = column.index; + this.current = index; + this.table[index] = column; + this.table.splice(index + 1); + this.lexerState = column.lexerState; + + // Incrementally keep track of results + this.results = this.finish(); + }; + + // nb. deprecated: use save/restore instead! + Parser.prototype.rewind = function(index) { + if (!this.options.keepHistory) { + throw new Error('set option `keepHistory` to enable rewinding') + } + // nb. recall column (table) indicies fall between token indicies. + // col 0 -- token 0 -- col 1 + this.restore(this.table[index]); + }; + + Parser.prototype.finish = function() { + // Return the possible parsings + var considerations = []; + var start = this.grammar.start; + var column = this.table[this.table.length - 1]; + column.states.forEach(function (t) { + if (t.rule.name === start + && t.dot === t.rule.symbols.length + && t.reference === 0 + && t.data !== Parser.fail) { + considerations.push(t); + } + }); + return considerations.map(function(c) {return c.data; }); + }; + + return { + Parser: Parser, + Grammar: Grammar, + Rule: Rule, + }; + +})(); + +var moo = (function() { + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + // polyfill assign(), so we support IE9+ + var assign = typeof Object.assign === 'function' ? Object.assign : + // https://tc39.github.io/ecma262/#sec-object.assign + function(target, sources) { + if (target == null) { + throw new TypeError('Target cannot be null or undefined'); + } + target = Object(target); + + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + if (source == null) continue + + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + return target + }; + + var hasSticky = typeof new RegExp().sticky === 'boolean'; + + /***************************************************************************/ + + function isRegExp(o) { return o && o.constructor === RegExp } + function isObject(o) { return o && typeof o === 'object' && o.constructor !== RegExp && !Array.isArray(o) } + + function reEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + } + function reGroups(s) { + var re = new RegExp('|' + s); + return re.exec('').length - 1 + } + function reCapture(s) { + return '(' + s + ')' + } + function reUnion(regexps) { + var source = regexps.map(function(s) { + return "(?:" + s + ")" + }).join('|'); + return "(?:" + source + ")" + } + + function regexpOrLiteral(obj) { + if (typeof obj === 'string') { + return '(?:' + reEscape(obj) + ')' + + } else if (isRegExp(obj)) { + // TODO: consider /u support + if (obj.ignoreCase) { throw new Error('RegExp /i flag not allowed') } + if (obj.global) { throw new Error('RegExp /g flag is implied') } + if (obj.sticky) { throw new Error('RegExp /y flag is implied') } + if (obj.multiline) { throw new Error('RegExp /m flag is implied') } + return obj.source + + } else { + throw new Error('not a pattern: ' + obj) + } + } + + function objectToRules(object) { + var keys = Object.getOwnPropertyNames(object); + var result = []; + for (var i=0; i 0) { + throw new Error("RegExp has capture groups: " + regexp + "\nUse (?: … ) instead") + } + if (!hasStates && (options.pop || options.push || options.next)) { + throw new Error("State-switching options are not allowed in stateless lexers (for token '" + options.tokenType + "')") + } + + // try and detect rules matching newlines + if (!options.lineBreaks && regexp.test('\n')) { + throw new Error('Rule should declare lineBreaks: ' + regexp) + } + + // store regex + parts.push(reCapture(pat)); + } + + var suffix = hasSticky ? '' : '|(?:)'; + var flags = hasSticky ? 'ym' : 'gm'; + var combined = new RegExp(reUnion(parts) + suffix, flags); + + return {regexp: combined, groups: groups, error: errorRule} + } + + function compile(rules) { + var result = compileRules(rules); + return new Lexer({start: result}, 'start') + } + + function compileStates(states, start) { + var keys = Object.getOwnPropertyNames(states); + if (!start) start = keys[0]; + + var map = Object.create(null); + for (var i=0; i', pop: true }, + beat_operators: ['|', '+', '-', '*', '/'] + } +}); + +let Nil = Symbol('Nil'); +let cast_bool = function (arg) { + if (arg === Nil || arg === false) { + return false; + } + else { + return true; + } +}; + +// does this have to be an Error? idc +class PlaybackError extends Error { + constructor(message, scope) { + super(`${message}\nScope: "${scope.name}"`); + } +} +/* Import-related errors */ +class ImportError extends PlaybackError { + constructor(message, scope) { + super(message, scope); + } +} +class NoSuchStyleError extends ImportError { + constructor(identifier, scope) { + super(`No style with the name "${identifier}" was imported`, scope); + } +} +class NoSuchTrackError extends ImportError { + constructor(style, track, scope) { + super(`No track with the name "${track}" exists in the style "${style}"`, scope); + } +} +class NoSuchPatternError extends ImportError { + constructor(style, track, pattern, scope) { + super(`Pattern "${style}.${track}.${pattern}" does not exist`, scope); + } +} +/* Function-related errors */ +class FunctionNameError extends PlaybackError { + constructor(identifier, scope) { + super(`No function exists with name "${identifier}"`, scope); + } +} +class FunctionScopeError extends PlaybackError { + constructor(message, scope) { + super(message, scope); + } +} +class FunctionArgumentsError extends PlaybackError { + constructor(message, scope) { + super(message, scope); + } +} +/* Pattern-related errors */ +class TooManyBeatsError extends PlaybackError { + constructor(scope) { + super('Pattern may only contain 1 BeatGroup. Try the join operator "&"', scope); + } +} +/* Beat-related errors*/ +class MelodicBeatInDrumBeatGroupError extends PlaybackError { + constructor(scope) { + super('Unexpected Melodic Beat in a Drum Beat Group', scope); + } +} +class DrumBeatInMelodicBeatGroupError extends PlaybackError { + constructor(scope) { + super('Unexpected Drum Beat in a Melodic Beat Group', scope); + } +} + +/* + * In Playback styles, basically any pair of curly brackets defines a scope + * which inherits settings from its parent scope but can overwrite them. + */ +class Scope { + constructor() { + this.defaultVars = new Map(); + this.vars = new Map(); + this.name = null; + this.type = null; + this.scope = null; + } + inherit() { + this.vars = new Map([...this.defaultVars, ...this.scope.vars]); + } + init(scope) { + this.scope = scope; + // in case this.vars was set in the constructor + this.vars = new Map([...this.defaultVars, ...this.scope.vars, ...this.vars]); + } +} + +class MetaStatement extends Scope { + constructor(functionCalls) { + super(); + this.name = '@meta'; + this.type = '@meta'; + this.functionCalls = functionCalls; + } + init(scope) { + this.scope = scope; + // nothing in here can be dynamic so resolve these at compile time + for (let functionCall of this.functionCalls) { + functionCall.init(this); + functionCall.execute(); + } + scope.metadata = this.vars; + } +} +class OptionsStatement extends Scope { + constructor(functionCalls) { + super(); + this.name = '@options'; + this.type = '@options'; + this.functionCalls = functionCalls; + } + init(scope) { + // nothing in here /should/ be dynamic so resolve these at compile time + for (let functionCall of this.functionCalls) { + functionCall.init(this); + functionCall.execute(); + } + this.scope = scope; + // in this case we're actually overwriting our scope's variables, not + // vise-versa + scope.vars = new Map([...scope.vars, ...this.vars]); + } +} +class ImportStatement { + constructor(path, identifier) { + this.path = path; + this.identifier = identifier; + } +} + +var drumJson = { + "26": "Silence", + "27": "High-Q", + "28": "Slap", + "29": "Scratch Push", + "30": "Scratch Pull", + "31": "Sticks", + "32": "Square Click", + "33": "Metronome Click", + "34": "Metronome Bell", + "35": "Acoustic Bass Drum", + "36": "Bass Drum", + "37": "Side Stick", + "38": "Acoustic Snare", + "39": "Hand Clap", + "40": "Electric Snare", + "41": "Low Floor Tom", + "42": "Closed Hi Hat", + "43": "High Floor Tom", + "44": "Pedal Hi-Hat", + "45": "Low Tom", + "46": "Open Hi-Hat", + "47": "Low-Mid Tom", + "48": "Hi-Mid Tom", + "49": "Crash Cymbal 1", + "50": "High Tom", + "51": "Ride Cymbal 1", + "52": "Chinese Cymbal", + "53": "Ride Bell", + "54": "Tambourine", + "55": "Splash Cymbal", + "56": "Cowbell", + "57": "Crash Cymbal 2", + "58": "Vibraslap", + "59": "Ride Cymbal 2", + "60": "Hi Bongo", + "61": "Low Bongo", + "62": "Mute Hi Conga", + "63": "Open Hi Conga", + "64": "Low Conga", + "65": "High Timbale", + "66": "Low Timbale", + "67": "High Agogo", + "68": "Low Agogo", + "69": "Cabasa", + "70": "Maracas", + "71": "Short Whistle", + "72": "Long Whistle", + "73": "Short Guiro", + "74": "Long Guiro", + "75": "Claves", + "76": "Hi Wood Block", + "77": "Low Wood Block", + "78": "Mute Cuica", + "79": "Open Cuica", + "80": "Mute Triangle", + "81": "Open Triangle", + "82": "Shaker", + "83": "Jingle Bell", + "84": "Bell Tree", + "85": "Castanets", + "86": "Mute Surdo", + "87": "Open Surdo" +}; + +const tonal = _Tonal__default || _Tonal; +/** + * There are some inconsistencies with the official MIDI drum names, this + * transformation will hopefully ease the pain there. + * Note: What's the more general word for case-folding? Just "normalizing"? Eh + * @param {string} name + * @return {string} + */ +function normalizeDrumName(name) { + return name.toLowerCase().replace(/ |-|_/g, ' '); +} +// make a map of drum names, which is the inverse of the given JSON file +let DRUM_MAP = new Map(); +for (let midi in drumJson) { + let name = normalizeDrumName(drumJson[midi]); + DRUM_MAP.set(name, midi); +} +/** + * Special pitch value meaning the note will be set later by a DrumBeatGroup + */ +let AwaitingDrum = Symbol('AwaitingDrum'); +class Note { + /** + * @param {Object} opts Options object. + * @param {number} opts.time The note's time, in beats. + * @param {string | symbol} opts.pitch A string representing the pitch and octave of the note. e.x. 'A4' + * @param {number} opts.duraion The note's duration, in beats. + * @param {number} opts.volume The note's volume, as a float 0-1 (inclusive). + */ + constructor(opts) { + this.time = opts.time; + this.pitch = opts.pitch; + this.duration = opts.duration; + this.volume = opts.volume; + } + /** + * An integer representing the MIDI pitch value of the note. + * @type {number} + */ + get midi() { + if (this.pitch === AwaitingDrum) { + return null; + } + else { + let drumValue = DRUM_MAP.get(normalizeDrumName(this.pitch)); + if (drumValue) { + return drumValue; + } + else { + return tonal.Note.midi(this.pitch); + } + } + } + /** + * An integer 0-127 that roughly correlates to volume + * @type {number} + */ + get velocity() { + return Math.floor(this.volume * 127); + } +} +class NoteSet extends Array { + constructor(...args) { + super(); + this.push(...args); + } +} + +let tonal$1 = {}; +(function(n){function t(n){"string"!=typeof n&&(n="");var t=T.exec(n);return t?[t[1].toUpperCase(),t[2].replace(/x/g,"##"),t[3],t[4]]:null}function r(n,t){return n=Math.round(n),(!0===t?G:I)[n%12]+(Math.floor(n/12)-1)}function e(n,t){for(var r=[];t--;r[t]=t+n);return r}function m(n,t){for(var r=[];t--;r[t]=n-t);return r}function i(n,t){return null===n||null===t?[]:nan(t)})}function P(n){return o(n).filter(function(n,t,r){return 0===t||n!==r[t-1]})}function M(n){return "string"!=typeof n?An:_n[n]||(_n[n]=xn(n))}function a(n){var t=(n+1)%7;return t<0?7+t:t}function l(n,t){if(1===arguments.length)return function(t){return l(n,t)};var r=Kn(n),e=Qn(t);if(null===r||null===e)return null;var m=1===r.length?[r[0]+e[0]]:[r[0]+e[0],r[1]+e[1]];return mn(Un(m[0],m[1]))}function c(n,t){if(1===arguments.length)return function(t){return c(n,t)};var r=Kn(n);return null===r?null:mn(Un(r[0]+t))}function s(n,t){if(1===arguments.length)return function(t){return s(n,t)};var r=Kn(n),e=Kn(t);return null===e||null===r?null:e[0]-r[0]}function f(n,t){return 1===arguments.length?function(t){return l(t,n)}:l(t,n)}function d(n,t,r){var e=Qn(n),m=Qn(t);if(null===e||null===m)return null;var i=[e[0]+r*m[0],e[1]+r*m[1]];return Dn(Wn(i))}function p(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,1)}function b(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,-1)}function h(n,t){if(1===arguments.length)return function(t){return h(n,t)};var r=Kn(n),e=Kn(t);if(null===r||null===e||r.length!==e.length)return null;var m=1===r.length?[e[0]-r[0],-Math.floor(7*(e[0]-r[0])/12)]:[e[0]-r[0],e[1]-r[1]];return Dn(Wn(m))}function v(n,t){if(1===arguments.length)return function(t){return v(n,t)};var r=L(n),e=L(t);return null!==r.midi&&null!==e.midi?e.midi-r.midi:null!==r.chroma&&null!==e.chroma?(e.chroma-r.chroma+12)%12:null}function A(n){if(y(n))return n;if(!Array.isArray(n))return "";var t=[0,0,0,0,0,0,0,0,0,0,0,0];return n.map(nt).forEach(function(n){t[n]=1;}),t.join("")}function g(n){return et=et||i(2048,4095).map(function(n){return n.toString(2)}),"number"==typeof n?et.filter(function(t){return rt(t)===n}):et.slice()}function j(n,t){t=!1!==t;var r=A(n).split("");return Mn(r.map(function(n,e){var m=u(e,r);return t&&"0"===m[0]?null:m.join("")}))}function y(n){return mt.test(n)}function O(n){return y(n)?Mn(n.split("").map(function(n,t){return "1"===n?it[t]:null})):[]}function x(n,t){return 1===arguments.length?function(t){return x(n,t)}:A(n)===A(t)}function _(n,t){return arguments.length>1?_(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t&n)===t})}function z(n,t){return arguments.length>1?z(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t|n)===t})}function q(n,t){return arguments.length>1?q(n)(t):(n=A(n),function(t){return "1"===n[nt(t)]})}function k(n,t){return 1===arguments.length?function(t){return k(n,t)}:t.filter(q(n))}function S(n,t){var r=D(n);return t=t||r[1],pt(t).map(l(r[0]))}function w(n){var t=D(n);return void 0!==Mt(t[1])}function D(n){if("string"!=typeof n)return ["",""];var t=n.indexOf(" "),r=R(n.substring(0,t))||R(n)||"",e=""!==r?n.substring(r.length+1):n;return [r,e.length?e:""]}function E(n,t){var r=C(n);return t=t||r[1],xt(t).intervals.map(l(r[0]))}function C(n){var r=t(n);return ""===r[0]?["",n]:"A"===r[0]&&"ug"===r[3]?["","aug"]:St.test(r[2])?[r[0]+r[1],r[2]+r[3]]:[r[0]+r[1]+r[2],r[3]]}var $="C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B".split(" "),F=function(n){return "string"!=typeof n?$.slice():$.filter(function(t){var r=t[1]||" ";return -1!==n.indexOf(r)})},G=F(" #"),I=F(" b"),T=/^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)$/,B=Object.freeze({pc:null,name:null,step:null,alt:null,oct:null,octStr:null,chroma:null,midi:null,freq:null}),N=[0,2,4,5,7,9,11],L=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var r=t(n);if(""===r[0]||""!==r[3])return B;var e=r[0],m=r[1],i=r[2],u={letter:e,acc:m,octStr:i};return u.pc=u.letter+u.acc,u.name=u.pc+i,u.step=(u.letter.charCodeAt(0)+3)%7,u.alt="b"===u.acc[0]?-u.acc.length:u.acc.length,u.oct=i.length?+i:null,u.chroma=(N[u.step]+u.alt+120)%12,u.midi=null!==u.oct?N[u.step]+u.alt+12*(u.oct+1):null,u.freq=J(u.midi),Object.freeze(u)}),R=function(n){return L(n).name},U=function(n){return L(n).pc},H=function(n){return L(n).midi||+n||null},J=function(n,t){return void 0===t&&(t=440),"number"==typeof n?Math.pow(2,(n-69)/12)*t:null},K=function(n){return L(n).freq||J(n)},Q=Math.log(2),V=Math.log(440),W=function(n){var t=12*(Math.log(n)-V)/Q+69;return Math.round(100*t)/100},X=function(n){return L(n).chroma},Y=function(n){return L(n).oct},Z=function(n){return "CDEFGAB"[n]},nn=function(n,t){return Array(t+1).join(n)},tn=function(n,t){return "number"!=typeof n?"":t(n)},rn=function(n){return tn(n,function(n){return n<0?nn("b",-n):nn("#",n)})},en=function(n,t){void 0===n&&(n={}),void 0===t&&(t=null);var r=t?Object.assign({},L(t),n):n,e=r.step,m=r.alt,i=r.oct,u=Z(e);if(!u)return null;var o=u+rn(m);return i||0===i?o+i:o},mn=en,un=function(n,t){var e=L(n),m=e.alt,i=e.chroma,u=e.midi;if(null===i)return null;var o=!1===t?m<0:m>0;return null===u?U(r(i,o)):r(u,o)},on=function(n){return un(n,!1)},Pn=Object.freeze({names:F,tokenize:t,props:L,name:R,pc:U,midi:H,midiToFreq:J,freq:K,freqToMidi:W,chroma:X,oct:Y,stepToLetter:Z,altToAcc:rn,from:en,build:mn,fromMidi:r,simplify:un,enharmonic:on}),Mn=function(n){return n.filter(function(n){return 0===n||n})},an=function(n){var t=H(n);return null!==t?t:H(n+"-100")},ln=function(n,t){void 0===t&&(t=Math.random);for(var r,e,m=n.length;m;)r=t()*m--|0,e=n[m],n[m]=n[r],n[r]=e;return n},cn=function(n){return 0===n.length?[[]]:cn(n.slice(1)).reduce(function(t,r){return t.concat(n.map(function(t,e){var m=r.slice();return m.splice(e,0,n[0]),m}))},[])},sn=Object.freeze({range:i,rotate:u,compact:Mn,sort:o,unique:P,shuffle:ln,permutations:cn}),fn=new RegExp("^([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})|(AA|A|P|M|m|d|dd)([-+]?\\d+)$"),dn=[0,2,4,5,7,9,11],pn=[0,1,2,3,4,5,6,5,4,3,2,1],bn="1P 2m 2M 3m 3M 4P 5P 6m 6M 7m 7M 8P".split(" "),hn=function(n){return "string"!=typeof n?bn.slice():bn.filter(function(t){return -1!==n.indexOf(t[1])})},vn=function(n){var t=fn.exec(n);return null===t?null:t[1]?[t[1],t[2]]:[t[4],t[3]]},An=Object.freeze({name:null,num:null,q:null,step:null,alt:null,dir:null,type:null,simple:null,semitones:null,chroma:null}),gn=function(n,t){return Array(Math.abs(t)+1).join(n)},jn=function(n,t){return "M"===t&&"M"===n?0:"P"===t&&"P"===n?0:"m"===t&&"M"===n?-1:/^A+$/.test(t)?t.length:/^d+$/.test(t)?"P"===n?-t.length:-t.length-1:null},yn=function(n,t){return 0===t?"M"===n?"M":"P":-1===t&&"M"===n?"m":t>0?gn("A",t):t<0?gn("d","P"===n?t:t+1):null},On=function(n){return (Math.abs(n)-1)%7},xn=function(n){var t=vn(n);if(null===t)return An;var r={num:+t[0],q:t[1]};return r.step=On(r.num),r.type="PMMPPMM"[r.step],"M"===r.type&&"P"===r.q?An:(r.name=""+r.num+r.q,r.dir=r.num<0?-1:1,r.simple=8===r.num||-8===r.num?r.num:r.dir*(r.step+1),r.alt=jn(r.type,r.q),r.oct=Math.floor((Math.abs(r.num)-1)/7),r.semitones=r.dir*(dn[r.step]+r.alt+12*r.oct),r.chroma=(r.dir*(dn[r.step]+r.alt)%12+12)%12,Object.freeze(r))},_n={},zn=function(n){return M(n).num},qn=function(n){return M(n).name},kn=function(n){return M(n).semitones},Sn=function(n){return M(n).chroma},wn=function(n){return "string"==typeof n&&(n=M(n).chroma),"number"==typeof n?pn[n%12]:null},Dn=function(n){void 0===n&&(n={});var t=n.num,r=n.step,e=n.alt,m=n.oct;void 0===m&&(m=1);var i=n.dir;if(void 0!==r&&(t=r+1+7*m),void 0===t)return null;var u=i<0?"-":"",o="PMMPPMM"[On(t)];return u+t+yn(o,e)},En=function(n){var t=M(n);return t===An?null:t.simple+t.q},Cn=function(n){var t=M(n);if(t===An)return null;var r=(7-t.step)%7,e="P"===t.type?-t.alt:-(t.alt+1);return Dn({step:r,alt:e,oct:t.oct,dir:t.dir})},$n=[1,2,2,3,3,4,5,5,6,6,7,7],Fn="P m M m M P d P m M m M".split(" "),Gn=function(n){var t=n<0?-1:1,r=Math.abs(n),e=r%12,m=Math.floor(r/12);return t*($n[e]+7*m)+Fn[e]},In=Object.freeze({names:hn,tokenize:vn,props:M,num:zn,name:qn,semitones:kn,chroma:Sn,ic:wn,build:Dn,simplify:En,invert:Cn,fromSemitones:Gn}),Tn=[0,2,4,-1,1,3,5],Bn=function(n){return Math.floor(7*n/12)},Nn=Tn.map(Bn),Ln=function(n){var t=n.step,r=n.alt,e=n.oct,m=n.dir;void 0===m&&(m=1);var i=Tn[t]+7*r;return null===e?[m*i]:[m*i,m*(e-Nn[t]-4*r)]},Rn=[3,0,4,1,5,2,6],Un=function(n,t,r){var e=Rn[a(n)],m=Math.floor((n+1)/7);return void 0===t?{step:e,alt:m,dir:r}:{step:e,alt:m,oct:t+4*m+Nn[e],dir:r}},Hn=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}},Jn=function(n){return Hn(function(t){var r=n(t);return null===r.name?null:Ln(r)})},Kn=Jn(L),Qn=Jn(M),Vn=function(n){return 7*n[0]+12*n[1]<0},Wn=function(n){return Vn(n)?Un(-n[0],-n[1],-1):Un(n[0],n[1],1)},Xn=Object.freeze({transpose:l,trFifths:c,fifths:s,transposeBy:f,addIntervals:d,add:p,subtract:b,interval:h,semitones:v}),Yn={chromatic:["1P 2m 2M 3m 3M 4P 4A 5P 6m 6M 7m 7M"],lydian:["1P 2M 3M 4A 5P 6M 7M"],major:["1P 2M 3M 4P 5P 6M 7M",["ionian"]],mixolydian:["1P 2M 3M 4P 5P 6M 7m",["dominant"]],dorian:["1P 2M 3m 4P 5P 6M 7m"],aeolian:["1P 2M 3m 4P 5P 6m 7m",["minor"]],phrygian:["1P 2m 3m 4P 5P 6m 7m"],locrian:["1P 2m 3m 4P 5d 6m 7m"],altered:["1P 2m 3m 3M 5d 6m 7m",["super locrian","diminished whole tone","pomeroy"]],iwato:["1P 2m 4P 5d 7m"],hirajoshi:["1P 2M 3m 5P 6m"],kumoijoshi:["1P 2m 4P 5P 6m"],pelog:["1P 2m 3m 5P 6m"],prometheus:["1P 2M 3M 4A 6M 7m"],ritusen:["1P 2M 4P 5P 6M"],scriabin:["1P 2m 3M 5P 6M"],piongio:["1P 2M 4P 5P 6M 7m"],augmented:["1P 2A 3M 5P 5A 7M"],neopolitan:["1P 2m 3m 4P 5P 6m 7M"],diminished:["1P 2M 3m 4P 5d 6m 6M 7M"],egyptian:["1P 2M 4P 5P 7m"],oriental:["1P 2m 3M 4P 5d 6M 7m"],spanish:["1P 2m 3M 4P 5P 6m 7m",["phrygian major"]],flamenco:["1P 2m 3m 3M 4A 5P 7m"],balinese:["1P 2m 3m 4P 5P 6m 7M"],persian:["1P 2m 3M 4P 5d 6m 7M"],bebop:["1P 2M 3M 4P 5P 6M 7m 7M"],enigmatic:["1P 2m 3M 5d 6m 7m 7M"],ichikosucho:["1P 2M 3M 4P 5d 5P 6M 7M"],"melodic minor":["1P 2M 3m 4P 5P 6M 7M"],"melodic minor second mode":["1P 2m 3m 4P 5P 6M 7m"],"lydian augmented":["1P 2M 3M 4A 5A 6M 7M"],"lydian dominant":["1P 2M 3M 4A 5P 6M 7m",["lydian b7"]],"melodic minor fifth mode":["1P 2M 3M 4P 5P 6m 7m",["hindu","mixolydian b6M"]],"locrian #2":["1P 2M 3m 4P 5d 6m 7m"],"locrian major":["1P 2M 3M 4P 5d 6m 7m",["arabian"]],"major pentatonic":["1P 2M 3M 5P 6M",["pentatonic"]],"lydian pentatonic":["1P 3M 4A 5P 7M",["chinese"]],"mixolydian pentatonic":["1P 3M 4P 5P 7m",["indian"]],"locrian pentatonic":["1P 3m 4P 5d 7m",["minor seven flat five pentatonic"]],"minor pentatonic":["1P 3m 4P 5P 7m"],"minor six pentatonic":["1P 3m 4P 5P 6M"],"minor hexatonic":["1P 2M 3m 4P 5P 7M"],"flat three pentatonic":["1P 2M 3m 5P 6M",["kumoi"]],"flat six pentatonic":["1P 2M 3M 5P 6m"],"major flat two pentatonic":["1P 2m 3M 5P 6M"],"whole tone pentatonic":["1P 3M 5d 6m 7m"],"ionian pentatonic":["1P 3M 4P 5P 7M"],"lydian #5P pentatonic":["1P 3M 4A 5A 7M"],"lydian dominant pentatonic":["1P 3M 4A 5P 7m"],"minor #7M pentatonic":["1P 3m 4P 5P 7M"],"super locrian pentatonic":["1P 3m 4d 5d 7m"],"in-sen":["1P 2m 4P 5P 7m"],"vietnamese 1":["1P 3m 4P 5P 6m"],"vietnamese 2":["1P 3m 4P 5P 7m"],"prometheus neopolitan":["1P 2m 3M 4A 6M 7m"],"major blues":["1P 2M 3m 3M 5P 6M"],"minor blues":["1P 3m 4P 5d 5P 7m",["blues"]],"composite blues":["1P 2M 3m 3M 4P 5d 5P 6M 7m"],"augmented heptatonic":["1P 2A 3M 4P 5P 5A 7M"],"dorian #4":["1P 2M 3m 4A 5P 6M 7m"],"lydian diminished":["1P 2M 3m 4A 5P 6M 7M"],"whole tone":["1P 2M 3M 4A 5A 7m"],"leading whole tone":["1P 2M 3M 4A 5A 7m 7M"],"harmonic minor":["1P 2M 3m 4P 5P 6m 7M"],"lydian minor":["1P 2M 3M 4A 5P 6m 7m"],"neopolitan minor":["1P 2m 3m 4P 5P 6m 7M"],"neopolitan major":["1P 2m 3m 4P 5P 6M 7M",["dorian b2"]],"neopolitan major pentatonic":["1P 3M 4P 5d 7m"],"romanian minor":["1P 2M 3m 5d 5P 6M 7m"],"double harmonic lydian":["1P 2m 3M 4A 5P 6m 7M"],"harmonic major":["1P 2M 3M 4P 5P 6m 7M"],"double harmonic major":["1P 2m 3M 4P 5P 6m 7M",["gypsy"]],"hungarian minor":["1P 2M 3m 4A 5P 6m 7M"],"hungarian major":["1P 2A 3M 4A 5P 6M 7m"],"spanish heptatonic":["1P 2m 3m 3M 4P 5P 6m 7m"],"todi raga":["1P 2m 3m 4A 5P 6m 7M"],"malkos raga":["1P 3m 4P 6m 7m"],"kafi raga":["1P 3m 3M 4P 5P 6M 7m 7M"],"purvi raga":["1P 2m 3M 4P 4A 5P 6m 7M"],"bebop dominant":["1P 2M 3M 4P 5P 6M 7m 7M"],"bebop minor":["1P 2M 3m 3M 4P 5P 6M 7m"],"bebop major":["1P 2M 3M 4P 5P 5A 6M 7M"],"bebop locrian":["1P 2m 3m 4P 5d 5P 6m 7m"],"minor bebop":["1P 2M 3m 4P 5P 6m 7m 7M"],"mystery #1":["1P 2m 3M 5d 6m 7m"],"minor six diminished":["1P 2M 3m 4P 5P 6m 6M 7M"],"ionian augmented":["1P 2M 3M 4P 5A 6M 7M"],"lydian #9":["1P 2m 3M 4A 5P 6M 7M"],"six tone symmetric":["1P 2m 3M 4P 5A 6M"]},Zn={M:["1P 3M 5P",["Major",""]],M13:["1P 3M 5P 7M 9M 13M",["maj13","Maj13"]],M6:["1P 3M 5P 13M",["6"]],M69:["1P 3M 5P 6M 9M",["69"]],M7add13:["1P 3M 5P 6M 7M 9M"],M7b5:["1P 3M 5d 7M"],M7b6:["1P 3M 6m 7M"],M7b9:["1P 3M 5P 7M 9m"],M7sus4:["1P 4P 5P 7M"],M9:["1P 3M 5P 7M 9M",["maj9","Maj9"]],M9b5:["1P 3M 5d 7M 9M"],M9sus4:["1P 4P 5P 7M 9M"],Madd9:["1P 3M 5P 9M",["2","add9","add2"]],Maj7:["1P 3M 5P 7M",["maj7","M7"]],Mb5:["1P 3M 5d"],Mb6:["1P 3M 13m"],Msus2:["1P 2M 5P",["add9no3","sus2"]],Msus4:["1P 4P 5P",["sus","sus4"]],Maddb9:["1P 3M 5P 9m"],m:["1P 3m 5P"],m11:["1P 3m 5P 7m 9M 11P",["_11"]],m11b5:["1P 3m 7m 12d 2M 4P",["h11","_11b5"]],m13:["1P 3m 5P 7m 9M 11P 13M",["_13"]],m6:["1P 3m 4P 5P 13M",["_6"]],m69:["1P 3m 5P 6M 9M",["_69"]],m7:["1P 3m 5P 7m",["minor7","_","_7"]],m7add11:["1P 3m 5P 7m 11P",["m7add4"]],m7b5:["1P 3m 5d 7m",["half-diminished","h7","_7b5"]],m9:["1P 3m 5P 7m 9M",["_9"]],m9b5:["1P 3m 7m 12d 2M",["h9","-9b5"]],mMaj7:["1P 3m 5P 7M",["mM7","_M7"]],mMaj7b6:["1P 3m 5P 6m 7M",["mM7b6"]],mM9:["1P 3m 5P 7M 9M",["mMaj9","-M9"]],mM9b6:["1P 3m 5P 6m 7M 9M",["mMaj9b6"]],mb6M7:["1P 3m 6m 7M"],mb6b9:["1P 3m 6m 9m"],o:["1P 3m 5d",["mb5","dim"]],o7:["1P 3m 5d 13M",["diminished","m6b5","dim7"]],o7M7:["1P 3m 5d 6M 7M"],oM7:["1P 3m 5d 7M"],sus24:["1P 2M 4P 5P",["sus4add9"]],madd4:["1P 3m 4P 5P"],madd9:["1P 3m 5P 9M"],4:["1P 4P 7m 10m",["quartal"]],5:["1P 5P"],7:["1P 3M 5P 7m",["Dominant","Dom"]],9:["1P 3M 5P 7m 9M",["79"]],11:["1P 5P 7m 9M 11P"],13:["1P 3M 5P 7m 9M 13M",["13_"]],64:["5P 8P 10M"],"M#5":["1P 3M 5A",["augmented","maj#5","Maj#5","+","aug"]],"M#5add9":["1P 3M 5A 9M",["+add9"]],"M13#11":["1P 3M 5P 7M 9M 11A 13M",["maj13#11","Maj13#11","M13+4","M13#4"]],"M6#11":["1P 3M 5P 6M 11A",["M6b5","6#11","6b5"]],"M69#11":["1P 3M 5P 6M 9M 11A"],"M7#11":["1P 3M 5P 7M 11A",["maj7#11","Maj7#11","M7+4","M7#4"]],"M7#5":["1P 3M 5A 7M",["maj7#5","Maj7#5","maj9#5","M7+"]],"M7#5sus4":["1P 4P 5A 7M"],"M7#9#11":["1P 3M 5P 7M 9A 11A"],"M9#11":["1P 3M 5P 7M 9M 11A",["maj9#11","Maj9#11","M9+4","M9#4"]],"M9#5":["1P 3M 5A 7M 9M",["Maj9#5"]],"M9#5sus4":["1P 4P 5A 7M 9M"],"11b9":["1P 5P 7m 9m 11P"],"13#11":["1P 3M 5P 7m 9M 11A 13M",["13+4","13#4"]],"13#9":["1P 3M 5P 7m 9A 13M",["13#9_"]],"13#9#11":["1P 3M 5P 7m 9A 11A 13M"],"13b5":["1P 3M 5d 6M 7m 9M"],"13b9":["1P 3M 5P 7m 9m 13M"],"13b9#11":["1P 3M 5P 7m 9m 11A 13M"],"13no5":["1P 3M 7m 9M 13M"],"13sus4":["1P 4P 5P 7m 9M 13M",["13sus"]],"69#11":["1P 3M 5P 6M 9M 11A"],"7#11":["1P 3M 5P 7m 11A",["7+4","7#4","7#11_","7#4_"]],"7#11b13":["1P 3M 5P 7m 11A 13m",["7b5b13"]],"7#5":["1P 3M 5A 7m",["+7","7aug","aug7"]],"7#5#9":["1P 3M 5A 7m 9A",["7alt","7#5#9_","7#9b13_"]],"7#5b9":["1P 3M 5A 7m 9m"],"7#5b9#11":["1P 3M 5A 7m 9m 11A"],"7#5sus4":["1P 4P 5A 7m"],"7#9":["1P 3M 5P 7m 9A",["7#9_"]],"7#9#11":["1P 3M 5P 7m 9A 11A",["7b5#9"]],"7#9#11b13":["1P 3M 5P 7m 9A 11A 13m"],"7#9b13":["1P 3M 5P 7m 9A 13m"],"7add6":["1P 3M 5P 7m 13M",["67","7add13"]],"7b13":["1P 3M 7m 13m"],"7b5":["1P 3M 5d 7m"],"7b6":["1P 3M 5P 6m 7m"],"7b9":["1P 3M 5P 7m 9m"],"7b9#11":["1P 3M 5P 7m 9m 11A",["7b5b9"]],"7b9#9":["1P 3M 5P 7m 9m 9A"],"7b9b13":["1P 3M 5P 7m 9m 13m"],"7b9b13#11":["1P 3M 5P 7m 9m 11A 13m",["7b9#11b13","7b5b9b13"]],"7no5":["1P 3M 7m"],"7sus4":["1P 4P 5P 7m",["7sus"]],"7sus4b9":["1P 4P 5P 7m 9m",["susb9","7susb9","7b9sus","7b9sus4","phryg"]],"7sus4b9b13":["1P 4P 5P 7m 9m 13m",["7b9b13sus4"]],"9#11":["1P 3M 5P 7m 9M 11A",["9+4","9#4","9#11_","9#4_"]],"9#11b13":["1P 3M 5P 7m 9M 11A 13m",["9b5b13"]],"9#5":["1P 3M 5A 7m 9M",["9+"]],"9#5#11":["1P 3M 5A 7m 9M 11A"],"9b13":["1P 3M 7m 9M 13m"],"9b5":["1P 3M 5d 7m 9M"],"9no5":["1P 3M 7m 9M"],"9sus4":["1P 4P 5P 7m 9M",["9sus"]],"m#5":["1P 3m 5A",["m+","mb6"]],"m11A 5":["1P 3m 6m 7m 9M 11P"],"m7#5":["1P 3m 6m 7m"],"m9#5":["1P 3m 6m 7m 9M"],"+add#9":["1P 3M 5A 9A"]},nt=function(n){return X(n)||Sn(n)||0},tt=function(n){return parseInt(A(n),2)},rt=function(n){return n.replace(/0/g,"").length},et=null,mt=/^[01]{12}$/,it="1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M".split(" "),ut=Object.freeze({chroma:A,chromas:g,modes:j,isChroma:y,intervals:O,isEqual:x,isSubsetOf:_,isSupersetOf:z,includes:q,filter:k}),ot=function(n){var t=Object.keys(n).sort(),r=[],e=[],m=function(n,t,m){r[n]=t,e[m]=e[m]||[],e[m].push(n);};t.forEach(function(t){var r=n[t][0].split(" "),e=n[t][1],i=A(r);m(t,r,i),e&&e.forEach(function(n){return m(n,r,i)});});var i=Object.keys(r).sort(),u=function(n){return r[n]};return u.names=function(n){return "string"==typeof n?(e[n]||[]).slice():(!0===n?i:t).slice()},u},Pt=function(n,t){var r=function(r){return n(r)||t(r)};return r.names=function(r){return n.names(r).concat(t.names(r))},r},Mt=ot(Yn),at=ot(Zn),lt=Pt(Mt,at),ct=Object.freeze({dictionary:ot,combine:Pt,scale:Mt,chord:at,pcset:lt}),st=Object.freeze({name:null,intervals:[],names:[],chroma:null,setnum:null}),ft=function(n,t){return function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=Mt(n);if(!t)return st;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=Mt.names(r.chroma),Object.freeze(r)},{}),dt=Mt.names,pt=function(n){var t=D(n);return ft(t[1]).intervals},bt=function(n){var t=pt(n),r=S(n);return j(t).map(function(n,e){var m=Mt.names(n)[0];if(m)return [r[e]||t[e],m]}).filter(function(n){return n})},ht=function(n){var t=_(pt(n));return at.names().filter(function(n){return t(at(n))})},vt=function(n){var t=Mn(n.map(U));if(!t.length)return t;var r=t[0],e=P(t);return u(e.indexOf(r),e)},At=function(n){if(!pt(n).length)return [];var t=z(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},gt=function(n){var t=_(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},jt=Object.freeze({props:ft,names:dt,intervals:pt,notes:S,exists:w,tokenize:D,modeNames:bt,chords:ht,toScale:vt,supersets:At,subsets:gt}),yt=at.names,Ot=Object.freeze({name:null,names:[],intervals:[],chroma:null,setnum:null}),xt=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=at(n);if(!t)return Ot;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=at.names(r.chroma),r}),_t=function(n){return xt(C(n)[1]).intervals},zt=function(n){return void 0!==at(C(n)[1])},qt=function(n){if(!_t(n).length)return [];var t=z(_t(n));return at.names().filter(function(n){return t(at(n))})},kt=function(n){var t=_(_t(n));return at.names().filter(function(n){return t(at(n))})},St=/^(6|64|7|9|11|13)$/,wt=Object.freeze({names:yt,props:xt,intervals:_t,notes:E,exists:zt,supersets:qt,subsets:kt,tokenize:C}),Dt=l,Et=h,Ct=L,$t=H,Ft=K,Gt=at,It=Mt;n.Array=sn,n.Note=Pn,n.Interval=In,n.Distance=Xn,n.Scale=jt,n.Chord=wt,n.PcSet=ut,n.Dictionary=ct,n.transpose=Dt,n.interval=Et,n.note=Ct,n.midi=$t,n.freq=Ft,n.chord=Gt,n.scale=It,Object.defineProperty(n,"__esModule",{value:!0});})(tonal$1); + +//import {Nil} from './type_utils.js'; +class MelodicBeatLiteral { + constructor(opts) { + this.time = opts.time || { time: 'auto' }; + this.pitch = opts.pitch; + this.octave = opts.octave || 'inherit'; + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + if (this.time.time === 'auto') { + return this.indexInMeasure + 1; + } + else { + return this.time.time; + } + } + /** + * Normalize a chord into a form tonal can handle + * @param {string} [chord=''] + * @return {string} + */ + static normalizeChord(chord = '') { + return chord + .replace(/-/g, '_') // tonal uses _ over - for minor7 + .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? + } + static chordToScaleName(chord) { + let chordType = tonal$1.Chord.tokenize(chord)[1]; + // @TODO: make this more robust + let names = tonal$1.Chord.props(chordType).names; + if (names.includes('dim')) + return 'diminished'; + if (names.includes('aug')) + return 'augmented'; + if (names.includes('Major')) + return 'major'; + if (names.includes('minor')) + return 'minor'; + if (names.includes('minor7')) + return 'dorian'; + if (names.includes('Dominant')) + return 'mixolydian'; + // if none of the above match, do our best to find the closest fit + let closestScale = 'major'; + names.forEach(name => { + if (name.startsWith('dim')) + closestScale = 'diminished'; + if (name.startsWith('aug')) + closestScale = 'augmented'; + if (name.startsWith('M')) + closestScale = 'major'; + if (name.startsWith('m')) + closestScale = 'minor'; + }); + return closestScale; + } + handleInversion(songIterator, pitches) { + let tonicPC = songIterator.song.getTransposedKey(); + let tonicNote = tonal$1.Note.from({ oct: this.getOctave() }, tonicPC); + let tonic = tonal$1.Note.midi(tonicNote); + let outPitches = []; + for (let pitchNote of pitches) { + let pitch = tonal$1.Note.midi(pitchNote); + if (pitch - tonic >= 6) + pitch -= 12; + outPitches.push(tonal$1.Note.fromMidi(pitch)); + } + return outPitches; + } + static getAnchorChord(anchor, songIterator, currentTime) { + let anchorChord; + switch (anchor) { + case 'KEY': { + anchorChord = songIterator.song.getTransposedKey(); + } + case 'NEXT': { + let nextMeasure = songIterator.getRelative(1); + if (nextMeasure) { + anchorChord = nextMeasure.beats[0].chord; + } + else { + anchorChord = songIterator.song.getTransposedKey(); + } + } + case 'STEP': + case 'ARPEGGIATE': + default: { + // crawl backward through this measure to get the last set beat + let lastSetBeat = Math.floor(currentTime); + let iteratorMeasure = songIterator.getRelative(0); + if (!iteratorMeasure) + break; + do { + const beat = iteratorMeasure.beats[lastSetBeat]; + anchorChord = beat && beat.chord; + lastSetBeat--; + } while (!anchorChord); + } + } + return this.normalizeChord(anchorChord); + } + static anchorChordToRoot(anchorChord, degree, octave) { + let anchorTonic = tonal$1.Chord.tokenize(anchorChord)[0]; + let anchorScaleName = this.chordToScaleName(anchorChord); + let scalePCs = tonal$1.Scale.notes(anchorTonic, anchorScaleName); + let rootPC = scalePCs[degree - 1]; + return tonal$1.Note.from({ oct: octave }, rootPC); + } + getAnchorData(songIterator) { + let anchorChord = MelodicBeatLiteral.getAnchorChord(this.pitch.anchor, songIterator, this.getTime()); + let root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, this.pitch.degree, this.getOctave()); + return [anchorChord, root]; + } + getPitches(songIterator) { + let [anchorChord, root] = this.getAnchorData(songIterator); + let pitches; + if (this.pitch.chord) { + // this feels extremely incorrect + // why would anyone need it to work this way + let anchorChordType = tonal$1.Chord.tokenize(anchorChord)[1]; + pitches = tonal$1.Chord.notes(root, anchorChordType); + } + else { + pitches = [root]; + } + if (this.scope.vars.get('invertible')) { + pitches = this.handleInversion(songIterator, pitches); + } + return pitches; + } + /** + * Returns true if the beat is anchored via STEP or ARPEGGIATE + * @returns {boolean} + */ + isDynamic() { + return ['STEP', 'ARPEGGIATE'].includes(this.pitch.anchor); + } + getOctave() { + if (this.octave === 'inherit') { + return this.scope.vars.get('octave'); + } + else { + return this.octave; + } + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + if (this.time.flag === 'STACCATO') { + return Math.min(0.25, duration); + } + else { + return duration; + } + } + getVolume() { + let volume = this.scope.vars.get('volume'); + if (this.time.flag === 'ACCENTED') + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let notes = new NoteSet(); + let time = this.getTime(); // @TODO: this varies with rolling + let pitches = this.getPitches(songIterator); + let duration = this.getDuration(); // @TODO: this varies with rolling + let volume = this.getVolume(); + for (let pitch of pitches) { + notes.push(new Note({ + time: time, + pitch: pitch, + duration: duration, + volume: volume + })); + } + return notes; + } +} +class DrumBeatLiteral { + constructor(opts) { + this.time = opts.time; + this.accented = opts.accented || false; + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + return this.time; + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + return duration; + } + getVolume() { + let volume = this.scope.vars.get('volume'); + if (this.accented) + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let time = this.getTime(); + let duration = this.getDuration(); + let volume = this.getVolume(); + return new NoteSet(new Note({ + time: time, + pitch: AwaitingDrum, + duration: duration, + volume: volume + })); + } +} + +let definitions = new Map(); +/** + * Make an assertion about argument count and types. + * @param {string} identifier The function name. + * @param {Array} args The arguments passed to the function. + * @param {Array.} types Array of the types (typeof) or classes + * (instanceof) to expect. + * @param {Scope} scope The scope, for error logging. + */ +function assertArgTypes(identifier, args, types, scope) { + if (types == '*') + return; + if (args.length != types.length) { + throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, scope); + } + for (let i in args) { + if (types[i] == '*') + continue; + let arg = args[i]; + if (arg instanceof FunctionCall) { + arg = arg.returns; + if (arg == '*') { + continue; // what's the correct functionality here? cry? + } + else if (typeof types[i] == 'string') { + if (arg != types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); + } + } + else { + if (arg != types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); + } + } + } + else { + if (typeof types[i] == 'string') { + if (typeof arg != types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); + } + } + else { + if (!(arg instanceof types[i])) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); + } + } + } + } +} +/** + * Make an assertion about the scope in which the function is called. + * @param {string} identifier The function's name. + * @param {string='no-meta'} goalscope One of 4 string options: + * - 'meta': the function throws if it's called outside a @meta block. + * - 'options': the function throws if it's called outside an @options block. + * - 'no-config': the function throws if it's called inside a @meta or @options + * block, but runs anywhere else that the parser will let you call a function. + * - 'pattern': the function throws if called outside a pattern scope. + * - 'no-meta' (default): the function throws if it's called inside a @meta + * block, but runs anywhere else that the parser will let you call a function. + * @param {Scope} scope The calling scope. + */ +function assertScope(identifier, goalscope = 'no-meta', scope) { + if (goalscope == 'meta') { + if (scope.type != '@meta') { + throw new FunctionScopeError(`Function "${identifier}" must only be called within a @meta block."`, scope); + } + } + else if (goalscope == 'options') { + if (scope.type != '@options') { + throw new FunctionScopeError(`Function "${identifier}" must only be called within an @options block."`, scope); + } + } + else if (goalscope == 'no-config') { + // ensure that config blocks can be resolved at compile time + if (scope.type == '@meta' || scope.type == '@options') { + throw new FunctionScopeError(`Function "${identifier}" must not be called within a @meta or @options block."`, scope); + } + } + else if (goalscope == 'pattern') { + if (scope.type != 'PatternExpressionGroup') { + throw new FunctionScopeError(`Function "${identifier}" must only be called within a @pattern block."`, scope); + } + // @TODO: what about @pattern foo private() -- makes no sense but yea + } + else if (goalscope == 'no-meta') { + if (scope.type == '@meta') { + throw new FunctionScopeError(`Function "${identifier}" must not be called within a @meta block."`, scope); + } + } +} +/** + * Define a function. + * @param {string} identifier The name of the function. + * @param {Object} opts Options passed. See below. + * @param {Array.|string='*'} opts.types If set, throw error + * unless the arguments passed to the function map to these. Can be strings + * (typeof) or classes (instanceof), or the single string '*' to accept + * anything. See assertArgTypes above. + * @param {string='no-meta'} opts.scope Throw error unless the calling + * scope matches. See assertScope above. + * @param {string|Function|Nil='*'} opts.returns The return type. If set to '*' + * it may return anything (for example, choose() returns one of whatever's + * passed to it regardless of type). + * @param {Function} func The function to run. It's passed 3 arguments: + * - args: an array of the arguments passed in the Playback function call. + * - scope: the calling scope. So it can set in scope.vars. + * - argErr: a function. If the function does further testing on its + * arguments and there's an issue, pass this the error message and it throws. + */ +let define$1 = function (identifier, opts, func) { + let definition = { + types: opts.types || '*', + returns: opts.returns || '*', + scope: opts.scope || 'no-meta', + execute: (args, songIterator, scope) => { + let argErr = message => { + throw new FunctionArgumentsError(message, scope); + }; + return func(args, songIterator, scope, argErr); + } + }; + definitions.set(identifier, definition); +}; +/** + * Quickly define a single-argument function that simply sets a var of the same + * name in its parent scope. + * @param {string} identifier The name of the function. + * @param {string|Function} type Throw unless the argument is of this type (see + * assertArgTypes above). + * @param {?string=null} goalscope Throw error unless the calling scope matches. + * See assertScope above. + */ +let defineVar = function (identifier, type, goalscope = null) { + let opts = { + types: [type], + scope: goalscope, + returns: Nil + }; + define$1(identifier, opts, (args, songIterator, scope, argErr) => { + scope.vars.set(identifier, args[0]); + return Nil; + }); +}; +/** + * Quickly define a function that sets a a var of the same name in its parent + * scope. If it has 0 args it sets the var to true, if it has 1 boolean arg + * it sets the var to that. + * @param {string} identifier The name of the function. + * @param {?string=null} goalscope Throw error unless the calling scope matches. + * See assertScope above. + */ +let defineBoolean = function (identifier, goalscope = null) { + let opts = { + types: '*', + scopes: goalscope, + returns: Nil + }; + define$1(identifier, opts, (args, songIterator, scope, argErr) => { + if (args.length) { + assertArgTypes(identifier, args, ['boolean'], scope); + scope.vars.set(identifier, args[0]); + } + else { + scope.vars.set(identifier, true); + } + return Nil; + }); +}; +/*********** ACTUAL FUNCTION DEFINITIONS ***********/ +/*** @meta functions ***/ +defineVar('name', 'string', 'meta'); +defineVar('author', 'string', 'meta'); +defineVar('description', 'string', 'meta'); +defineVar('playback-version', 'number', 'meta'); +/*** @options functions ***/ +define$1('time-signature', { + types: ['number', 'number'], + scope: 'options', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (!Number.isInteger(Math.log2(args[1]))) { + argErr('Argument 2 of "time-signature" must be a power of 2.'); + } + scope.vars.set('time-signature', [args[0], args[1]]); + return Nil; +}); +defineBoolean('swing', 'options'); +/*** anywhere but @meta functions ***/ +define$1('volume', { + types: ['number'], + scope: 'no-meta', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (args[0] < 0 || args[0] > 1) { + argErr('Argument 1 of "volume" must be in range 0-1 (inclusive).'); + } + scope.vars.set('volume', args[0]); + return Nil; +}); +defineBoolean('invertible', 'no-meta'); +define$1('octave', { + types: ['number'], + scope: 'no-meta', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { + argErr('Argument 1 of "octave" must be an integer 0-9.'); + } + scope.vars.set('octave', args[0]); + return Nil; +}); +/*** anywhere but config functions (strictly dynamic functions) ***/ +define$1('choose', { + types: '*', + scope: 'no-config', + returns: '*' +}, (args, songIterator, scope, argErr) => { + let nonNilArgs = args.filter(arg => arg !== Nil); + if (nonNilArgs.length) { + let index = Math.floor(Math.random() * nonNilArgs.length); + return nonNilArgs[index]; + } + else { + return Nil; + } +}); +let anchorOrNumberToChordAndRoot = function (arg, songIterator) { + let anchorChord, root; + if (typeof arg == 'number') { + anchorChord = MelodicBeatLiteral.getAnchorChord(null, songIterator, 1); + root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, arg, 4); + } + else if (arg.anchor) { + anchorChord = MelodicBeatLiteral.getAnchorChord(arg.anchor, songIterator, 1); + root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, 1, 4); + } + return [anchorChord, root]; +}; +define$1('progression', { + types: '*', + scope: 'no-config', + returns: 'boolean' +}, (args, songIterator, scope, argErr) => { + for (let i in args) { + let arg = args[i]; + let [, goal] = anchorOrNumberToChordAndRoot(arg, songIterator); + if (!goal) { + argErr('Arguments of "progression" must be numbers or anchors.'); + } + let actualMeasure = songIterator.getRelative(Number(i)); + if (!actualMeasure) + return false; + let actualChord = MelodicBeatLiteral.normalizeChord(actualMeasure.beats[0].chord); + let actual = MelodicBeatLiteral.anchorChordToRoot(actualChord, 1, 4); + if (actual != goal) + return false; + } + return true; +}); +define$1('in-scale', { + types: '*', + scope: 'no-config', + returns: 'boolean' +}, (args, songIterator, scope, argErr) => { + let [, note] = anchorOrNumberToChordAndRoot(args[0], songIterator); + let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); + if (!note || !goalChord) { + argErr('Arguments of "in-scale" must be numbers or anchors.'); + } + let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); + let goalScale = tonal$1.Scale.notes(goalTonic, goalScaleName); + return goalScale.includes(note); +}); +define$1('beat-defined', { + types: ['number'], + scope: 'no-config', + returns: 'boolean' +}, (args, songIterator, scope, argErr) => { + let measure = songIterator.getRelative(0); + if (!measure) + return false; + return measure.beats[args[0]].chord !== null; +}); +/*** pattern-only functions ***/ +defineBoolean('private', 'pattern'); +defineVar('length', 'number', 'pattern'); +define$1('chance', { + types: ['number'], + scope: 'pattern', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (args[0] < 0 || args[0] > 1) { + argErr('Argument 1 of "chance" must be in range 0-1 (inclusive).'); + } + scope.vars.set('chance', args[0]); + return Nil; +}); + +/** + * If the value is a FunctionCall, call it and return the returned value. + * Otherwise, return the value itself. + * @private + */ // @TODO: if this is needed elsewhere, put it somewhere useful. +class FunctionCall { + /** + * @constructor + * @param {string} identifier The name of the function. Ideally it should + * match the name of one of the functions in function_data.js + */ + constructor(identifier, args) { + this.identifier = identifier; + this.definition = definitions.get(identifier); + this.args = args; + this.scope = null; + } + init(scope) { + this.scope = scope; + if (!this.definition) { + throw new FunctionNameError(this.identifier, this.scope); + } + this.returns = this.definition.returns; + assertScope(this.identifier, this.definition.scope, this.scope); + this.args.forEach(arg => { + if (arg.init) + arg.init(scope); + }); + assertArgTypes(this.identifier, this.args, this.definition.types, this.scope); + } + link(ASTs, parentStyle, parentTrack) { + this.args.forEach(arg => { + if (arg.link) + arg.link(ASTs, parentStyle, parentTrack); + }); + } + execute(songIterator) { + if (!this.scope) + throw new Error('function not initialized :('); + let evaluatedArgs = this.args.map(arg => { + if (arg.execute) { + return arg.execute(songIterator); + } + else { + return arg; + } + }); + let returnValue = this.definition.execute(evaluatedArgs, songIterator, this.scope); + if (returnValue === undefined) { + throw new Error(`Function "${this.identifier}" can return undefined`); + } + return returnValue; + } +} + +class PatternExpressionGroup extends Scope { + constructor(expressions) { + super(); + this.type = 'PatternExpressionGroup'; + this.name = '@pattern()'; + this.defaultVars.set('private', false); + this.defaultVars.set('chance', 1); + this.expressions = expressions; + this.functionCalls = []; + this.nonFunctionCallExpressions = []; + } + init(scope, patternStatement = null) { + super.init(scope); + this.patternStatement = patternStatement; + if (this.patternStatement) { + this.name = `@pattern(${this.patternStatement})`; + } + this.expressions.forEach(expression => { + if (expression.init) { + expression.init(this); + } + else { + throw ['expression not initialized:', expression]; + } + if (expression instanceof FunctionCall) { + this.functionCalls.push(expression); + } + else { + this.nonFunctionCallExpressions.push(expression); + } + }); + } + link(ASTs, parentStyle, parentTrack) { + this.expressions.forEach(expression => { + expression.link(ASTs, parentStyle, parentTrack); + }); + } + execute(songIterator, callerIsTrack = false) { + this.inherit(); + let beats = Nil; + for (let function_call of this.functionCalls) { + let return_value = function_call.execute(songIterator); + if (return_value instanceof NoteSet) { + if (beats !== Nil) { + throw new TooManyBeatsError(this); + } + beats = return_value; + } + } + if (callerIsTrack && this.vars.get('private') === true) { + return Nil; // if it's private we can give up now + } + for (let expression of this.nonFunctionCallExpressions) { + if (expression.execute) { + expression = expression.execute(songIterator); + } + if (expression instanceof NoteSet) { + if (beats !== Nil) { + throw new TooManyBeatsError(this); + } + beats = expression; + } + } + return beats; + } +} +class PatternStatement extends PatternExpressionGroup { + constructor(opts) { + if (opts.expression instanceof PatternExpressionGroup) { + // unroll the redundant expression group + super(opts.expression.expressions); + } + else { + super([opts.expression]); + } + this.identifier = opts.identifier; + this.condition = (opts.condition !== undefined) ? opts.condition : null; + } + getChance() { + return this.vars.get('chance'); + } + link(ASTs, parentStyle, parentTrack) { + super.link(ASTs, parentStyle, parentTrack); + if (this.condition && this.condition.link) { + this.condition.link(ASTs, parentStyle, parentTrack); + } + } + init(scope) { + super.init(scope); + if (this.condition && this.condition.init) + this.condition.init(this); + } + execute(songIterator, callerIsTrack = false) { + if (this.condition) { + let condition_value; + if (this.condition.execute) { + condition_value = this.condition.execute(songIterator); + } + else { + condition_value = this.condition; + } + if (cast_bool(condition_value) === false) + return Nil; + } + return super.execute(songIterator, callerIsTrack); + } +} +class PatternCall { + constructor(opts) { + this.import = opts.import || null; + this.track = opts.track || null; + this.pattern = opts.pattern; + this.scope = null; + this.patternStatement = null; + this.prettyprintname = (this.import || 'this') + '.' + + (this.track || 'this') + '.' + + this.pattern; + } + getChance() { + return this.patternStatement.getChance()(); + } + init(scope) { + this.scope = scope; + } + link(ASTs, parentStyle, parentTrack) { + let ast; + if (this.import === null) { + ast = parentStyle; + } + else { + // get path name of style + let importPath = parentStyle.importedStyles.get(this.import); + ast = ASTs.get(importPath); + if (!ast) + throw new NoSuchStyleError(this.import, this); + } + let track; + if (this.track === null) { + track = parentTrack; + } + else { + track = ast.tracks.get(this.track); + if (!track) + throw new NoSuchTrackError(this.import || 'this', this.track || 'this', this); + } + let patternStatement = track.patterns.get(this.pattern); + if (!patternStatement) + throw new NoSuchPatternError(this.import || 'this', this.track || 'this', this.pattern, this); + this.patternStatement = patternStatement; + } + execute(songIterator) { + // called patternStatement ignores private() + return this.patternStatement.execute(songIterator); + } +} +class JoinedPatternExpression { + constructor(patterns) { + this.patterns = patterns; + } + init(scope) { + this.scope = scope; + this.patterns.forEach(pattern => { + if (pattern.init) + pattern.init(scope); + }); + } + link(ASTs, parentStyle, parentTrack) { + this.patterns.forEach(pattern => { + pattern.link(ASTs, parentStyle, parentTrack); + }); + } + execute(songIterator) { + let noteSets = []; + for (let pattern of this.patterns) { + if (pattern.execute) { + pattern = pattern.execute(songIterator); + } + if (pattern instanceof NoteSet) { + noteSets.push(pattern); + } + } + if (noteSets.length) { + return (new NoteSet()).concat(...noteSets); + } + else { + return Nil; + } + } +} + +class TrackStatement extends Scope { + constructor(opts) { + super(); + this.name = opts.identifier; + this.type = '@track'; + this.defaultVars.set('octave', 4); + this.defaultVars.set('volume', 1); + this.defaultVars.set('private', false); + this.instrument = opts.instrument; + this.identifier = opts.identifier; + this.members = opts.members; + } + init(scope) { + super.init(scope); + this.functionCalls = []; + this.patterns = new Map(); + this.patternCalls = []; + this.members.forEach(member => { + // initialize them all now, var inheritence is handled during execution + member.init(this); + if (member instanceof FunctionCall) { + this.functionCalls.push(member); + } + else if (member instanceof PatternStatement) { + this.patterns.set(member.identifier, member); + } + else if (member instanceof PatternCall) { + this.patternCalls.push(member); + } + }); + } + link(ASTs, parentStyle) { + for (let patternCall of this.patternCalls) { + patternCall.link(ASTs, parentStyle, this); + this.patterns.set(patternCall.prettyprintname, patternCall); + } + for (let [, pattern] of this.patterns) { + pattern.link(ASTs, parentStyle, this); + } + } + execute(songIterator) { + this.inherit(); + console.log(`executing TrackStatement "${this.name}"`); + this.functionCalls.forEach(function_call => { + function_call.execute(songIterator); + }); + // weighted random picking + // https://stackoverflow.com/a/4463613/1784306 + // I don't really understand the above explanation, this is probs wrong + let totalWeight = 0; + let weightedOptions = []; + for (let [patternname, pattern] of this.patterns) { + console.log(`- pattern "${patternname}":`); + // true = I'm the instrument so if you're private return Nil + let result = pattern.execute(songIterator, true); + console.log(' - Result:', result); + // @TODO: handle multi-measure patterns (via locks?) + if (result !== Nil) { + for (let note of result) { + if (note.pitch === AwaitingDrum) { + throw new DrumBeatInMelodicBeatGroupError(pattern); + } + } + let chance = pattern.getChance(); + weightedOptions.push({ + noteSet: result, + lower: totalWeight, + upper: totalWeight + chance + }); + totalWeight += chance; + } + } + // binary search would make sense here if I expected more items + let goal = Math.random() * totalWeight; + for (let option of weightedOptions) { + if (option.lower <= goal && goal <= option.upper) { + console.log(' - Final result:', option.noteSet); + return option.noteSet; + } + } + console.log(' - Final result:', Nil); + return Nil; + } +} +class TrackCall { + constructor(opts) { + this.import = opts.import; + this.track = opts.track; + this.trackStatement = null; // will be set by the loader. + } + execute(songIterator) { + this.trackStatement.execute(songIterator); + } +} + +class GlobalScope extends Scope { + constructor(statements) { + super(); + this.name = 'global'; + this.type = 'global'; + this.statements = statements; + } + init() { + // set some default values + this.vars.set('time-signature', [4, 4]); + this.vars.set('tempo', 120); + this.tracks = new Map(); + this.metaStatements = []; + // @TODO: stop circular dependencies? cache them and mark one as mom + this.importedStyles = new Map(); + this.trackCalls = []; + this.dependencies = []; + for (let statement of this.statements) { + if (statement instanceof MetaStatement + || statement instanceof OptionsStatement) { + // @TODO: make sure there's exactly 1 meta block + this.metaStatements.push(statement); + } + else if (statement instanceof ImportStatement) { + this.importedStyles.set(statement.identifier, statement.path); + this.dependencies.push(statement.path); + } + else if (statement instanceof TrackStatement) { + this.tracks.set(statement.name, statement); + } + else if (statement instanceof TrackCall) { + this.trackCalls.push(statement); + } + } + // handle meta blocks first since they set variables in own scope + this.metaStatements.forEach(statement => statement.init(this)); + // -- handle importing before statements -- + this.tracks.forEach(statement => statement.init(this)); + } + link(ASTs) { + for (let trackCall of this.trackCalls) { + // get path name of style + let importPath = this.importedStyles.get(trackCall.import); + let ast = ASTs.get(importPath); + if (!ast) + throw new NoSuchStyleError(trackCall.import, this); + let trackStatement = ast.tracks.get(trackCall.track); + if (!trackStatement) + throw new NoSuchTrackError(trackCall.import, trackCall.track, this); + //trackCall.trackStatement = trackStatement; + this.tracks.set(`${trackCall.import}.${trackCall.track}`, trackStatement); + } + for (let [, track] of this.tracks) { + track.link(ASTs, this); + } + } + execute(songIterator) { + let trackNoteMap = new Map(); + for (let [, track] of this.tracks) { + let trackNotes = track.execute(songIterator); + if (trackNotes !== Nil) + trackNoteMap.set(track.instrument, trackNotes); + } + return trackNoteMap; + } + getInstruments() { + let instruments = new Set(); + for (let [, track] of this.tracks) { + instruments.add(track.instrument); + } + return instruments; + } +} + +class AnchorArgument { + constructor(anchor) { + this.anchor = anchor; + } +} +class BooleanOperator { + constructor(...args) { + this.args = args; + } + link(ASTs, parentStyle, parentTrack) { + this.args.forEach(arg => { + if (arg.link) + arg.link(ASTs, parentStyle, parentTrack); + }); + } + init(scope) { + this.scope = scope; + this.args.forEach(arg => { + if (arg.init) + arg.init(scope); + }); + } + resolve_args(songIterator) { + return this.args.map(arg => { + if (arg.execute) { + return arg.execute(songIterator); + } + else { + return arg; + } + }); + } +} +class BooleanNot extends BooleanOperator { + constructor(...args) { + super(...args); + } + execute(songIterator) { + let args = this.resolve_args(songIterator); + return !cast_bool(args[0]); + } +} +class BooleanAnd extends BooleanOperator { + constructor(...args) { + super(...args); + } + execute(songIterator) { + // sorry no short-circuiting because this code is prettier + // @TODO: add short-circuiting if this actually makes it too slow + let args = this.resolve_args(songIterator); + return cast_bool(args[0]) && cast_bool(args[1]); + } +} +class BooleanOr extends BooleanOperator { + constructor(...args) { + super(...args); + } + execute(songIterator) { + let args = this.resolve_args(songIterator); + return cast_bool(args[0]) || cast_bool(args[1]); + } +} + +class BeatGroupLiteral { + constructor(measures) { + this.measures = measures; + this.scope = null; + } + init(scope) { + this.scope = scope; + this.measures.forEach((measure, i) => measure.init(scope, this, i)); + } + link() { return; } + execute(songIterator) { + let joinedMeasures = new NoteSet(); + for (let i = 0; i < this.measures.length; i++) { + let offset = i * 4; // @TODO: pull in actual meter somehow + let measureNotes = this.measures[i].execute(songIterator); + if (measureNotes === Nil) + return Nil; // lets a/s abort the beatgroup + for (let measureNote of measureNotes) { + measureNote.time += offset; + joinedMeasures.push(measureNote); + } + } + return joinedMeasures; + } + getNextStaticBeatRoot(measureIndex, beatIndex, songIterator) { + // first, try every subsequent beat in the beatGroup + // (including subsequent measures) + let measure, beat; + while (measure = this.parentBeatGroup.measures[measureIndex++]) { + while (beat = measure.beats[++beatIndex]) { + if (!beat.isDynamic()) { + return beat.getAnchorData(songIterator)[1]; + } + } + beatIndex = -1; + } + // if there are no non-dynamic beats in the rest of the beat-group, return + // the first note of the next measure (@TODO: could be multiple measures + // later if it's a multi-measure beatgroup) + // @TODO: wtf? + const nextMeasure = songIterator.getRelative(1); + return MelodicBeatLiteral.normalizeChord(nextMeasure && nextMeasure.beats[0].chord); + } +} +class Measure { + constructor(beats) { + this.beats = beats; + this.beatsPerMeasure = null; + this.scope = null; + } + calculateDurationAfter(beatIndex) { + let currentBeat = this.beats[beatIndex]; + let currentBeatTime = currentBeat.getTime(); + let nextBeatTime; + if (beatIndex + 1 >= this.beats.length) { + nextBeatTime = this.beatsPerMeasure + 1; + } + else { + let nextBeat = this.beats[beatIndex + 1]; + nextBeatTime = nextBeat.getTime(); + } + return nextBeatTime - currentBeatTime; + } + getNextStaticBeatRoot(beatIndex, songIterator) { + return this.parentBeatGroup.getNextStaticBeatRoot(this.indexInBeatGroup, beatIndex, songIterator); + } + init(scope, parentBeatGroup, indexInBeatGroup) { + this.scope = scope; + this.parentBeatGroup = parentBeatGroup; + this.indexInBeatGroup = indexInBeatGroup; + this.beatsPerMeasure = this.scope.vars.get('time-signature')[0]; + // @TODO does this need more math? + this.beats.forEach((beat, i) => { + beat.init(scope, this, i); + }); + } + execute(songIterator) { + // clear cached notes (used for STEP/ARPEGGIATE interpolation) + for (let beat of this.beats) { + if (beat instanceof MelodicBeatLiteral) + beat.cachedAnchor = null; + } + // each beat returns a NoteSet since it could be a chord or whatever + let joined = new NoteSet(); + for (let beat of this.beats) { + let notes = beat.execute(songIterator); + if (notes === Nil) + return Nil; // lets a and s abort the beatgroup. + joined.push(...notes); + } + return joined; + } +} +class DrumBeatGroupLiteral { + constructor(drum, beatGroup) { + this.drum = drum; + this.beatGroup = beatGroup; // for now there's no diff in functionality... + // @TODO make sure our beats are all drummy + } + init(scope) { + this.scope = scope; + if (this.beatGroup.init) + this.beatGroup.init(scope); + } + link() { return; } // @TODO: I think patterncalls are allowed here? + execute(songIterator) { + let notes = this.beatGroup.execute(songIterator); + for (let note of notes) { + if (note.pitch === AwaitingDrum) { + note.pitch = this.drum; // @TODO: convert to number? + } + else { + throw new MelodicBeatInDrumBeatGroupError(this.scope); + } + } + return notes; + } +} + +// Generated automatically by nearley, version 2.13.0 +// http://github.com/Hardmath123/nearley +function id(x) { return x[0]; } +let Lexer = lexer; +let ParserRules = [ + {"name": "main$macrocall$2", "symbols": ["TopLevelStatement"]}, + {"name": "main$macrocall$1$ebnf$1", "symbols": []}, + {"name": "main$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "main$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "main$macrocall$1$ebnf$1", "symbols": ["main$macrocall$1$ebnf$1", "main$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "main$macrocall$1", "symbols": ["main$macrocall$2", "main$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "main", "symbols": ["_?", "main$macrocall$1", "_?"], "postprocess": d => new GlobalScope(d[1])}, + {"name": "TopLevelStatement", "symbols": ["ConfigurationStatement"], "postprocess": id}, + {"name": "TopLevelStatement", "symbols": ["ImportStatement"], "postprocess": id}, + {"name": "TopLevelStatement", "symbols": ["TrackStatement"], "postprocess": id}, + {"name": "TopLevelStatement", "symbols": ["TrackCallStatement"], "postprocess": id}, + {"name": "ConfigurationStatement", "symbols": [{"literal":"@meta"}, "_?", {"literal":"{"}, "_?", "ConfigurationList", "_?", {"literal":"}"}], "postprocess": d => new MetaStatement(d[4])}, + {"name": "ConfigurationStatement", "symbols": [{"literal":"@options"}, "_?", {"literal":"{"}, "_?", "ConfigurationList", "_?", {"literal":"}"}], "postprocess": d => new OptionsStatement(d[4])}, + {"name": "ConfigurationList$macrocall$2", "symbols": ["FunctionCallExpression"]}, + {"name": "ConfigurationList$macrocall$1$ebnf$1", "symbols": []}, + {"name": "ConfigurationList$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "ConfigurationList$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "ConfigurationList$macrocall$1$ebnf$1", "symbols": ["ConfigurationList$macrocall$1$ebnf$1", "ConfigurationList$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "ConfigurationList$macrocall$1", "symbols": ["ConfigurationList$macrocall$2", "ConfigurationList$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "ConfigurationList", "symbols": ["ConfigurationList$macrocall$1"], "postprocess": id}, + {"name": "ImportStatement", "symbols": [{"literal":"@import"}, "_", "StringLiteral", "_", {"literal":"as"}, "_", "Identifier"], "postprocess": d => new ImportStatement(d[2], d[6])}, + {"name": "TrackStatement$macrocall$2", "symbols": ["TrackMember"]}, + {"name": "TrackStatement$macrocall$1$ebnf$1", "symbols": []}, + {"name": "TrackStatement$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "TrackStatement$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "TrackStatement$macrocall$1$ebnf$1", "symbols": ["TrackStatement$macrocall$1$ebnf$1", "TrackStatement$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "TrackStatement$macrocall$1", "symbols": ["TrackStatement$macrocall$2", "TrackStatement$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "TrackStatement", "symbols": [{"literal":"@track"}, "_", "StringLiteral", "_", {"literal":"as"}, "_", "Identifier", "_?", {"literal":"{"}, "_?", "TrackStatement$macrocall$1", "_?", {"literal":"}"}], "postprocess": d => new TrackStatement({instrument: d[2], identifier: d[6], members: d[10]})}, + {"name": "TrackMember", "symbols": ["FunctionCallExpression"], "postprocess": id}, + {"name": "TrackMember", "symbols": ["PatternStatement"], "postprocess": id}, + {"name": "TrackMember", "symbols": ["PatternCallExpression"], "postprocess": id}, + {"name": "TrackCallStatement", "symbols": [{"literal":"@track"}, "_?", {"literal":"("}, "_?", "Identifier", {"literal":"."}, "Identifier", "_?", {"literal":")"}], "postprocess": d => new TrackCall({import: d[4], track: d[6]})}, + {"name": "PatternStatement", "symbols": [{"literal":"@pattern"}, "_", "Identifier", "_", "PatternConditional", "_?", "PatternExpression"], "postprocess": d => new PatternStatement({identifier: d[2], expression: d[6], condition: d[4]})}, + {"name": "PatternStatement", "symbols": [{"literal":"@pattern"}, "_", "Identifier", "_", "PatternExpression"], "postprocess": d => new PatternStatement({identifier: d[2], expression: d[4]})}, + {"name": "PatternConditional", "symbols": [{"literal":"if"}, "_?", {"literal":"("}, "_?", "FunctionCallArgument", "_?", {"literal":")"}], "postprocess": d => d[4]}, + {"name": "PatternExpression", "symbols": ["PatternExpression_NoJoin"], "postprocess": id}, + {"name": "PatternExpression", "symbols": ["JoinedPatternExpression"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["PatternExpressionGroup"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["BeatGroupLiteral"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["DrumBeatGroupLiteral"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["FunctionCallExpression"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["PatternCallExpression"], "postprocess": id}, + {"name": "PatternExpressionGroup$macrocall$2", "symbols": ["PatternExpression"]}, + {"name": "PatternExpressionGroup$macrocall$1$ebnf$1", "symbols": []}, + {"name": "PatternExpressionGroup$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "PatternExpressionGroup$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "PatternExpressionGroup$macrocall$1$ebnf$1", "symbols": ["PatternExpressionGroup$macrocall$1$ebnf$1", "PatternExpressionGroup$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "PatternExpressionGroup$macrocall$1", "symbols": ["PatternExpressionGroup$macrocall$2", "PatternExpressionGroup$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "PatternExpressionGroup", "symbols": [{"literal":"{"}, "_?", "PatternExpressionGroup$macrocall$1", "_?", {"literal":"}"}], "postprocess": d => new PatternExpressionGroup(d[2])}, + {"name": "PatternCallExpression", "symbols": [{"literal":"@pattern"}, "_?", {"literal":"("}, "_?", "Identifier", "_?", {"literal":")"}], "postprocess": d => new PatternCall({pattern: d[4]})}, + {"name": "PatternCallExpression", "symbols": [{"literal":"@pattern"}, "_?", {"literal":"("}, "_?", "Identifier", {"literal":"."}, "Identifier", "_?", {"literal":")"}], "postprocess": d => new PatternCall({track: d[4], pattern: d[6]})}, + {"name": "PatternCallExpression", "symbols": [{"literal":"@pattern"}, "_?", {"literal":"("}, "_?", "Identifier", {"literal":"."}, "Identifier", {"literal":"."}, "Identifier", "_?", {"literal":")"}], "postprocess": d => new PatternCall({import: d[4], track: d[6], pattern: d[8]})}, + {"name": "JoinedPatternExpression$macrocall$2", "symbols": ["PatternExpression_NoJoin"]}, + {"name": "JoinedPatternExpression$macrocall$3", "symbols": [{"literal":"&"}]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_?", "JoinedPatternExpression$macrocall$3", "_?", "JoinedPatternExpression$macrocall$2"], "postprocess": d => d[3][0]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1", "symbols": ["JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$1"]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$2", "symbols": ["_?", "JoinedPatternExpression$macrocall$3", "_?", "JoinedPatternExpression$macrocall$2"], "postprocess": d => d[3][0]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1", "symbols": ["JoinedPatternExpression$macrocall$1$ebnf$1", "JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "JoinedPatternExpression$macrocall$1", "symbols": ["JoinedPatternExpression$macrocall$2", "JoinedPatternExpression$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "JoinedPatternExpression", "symbols": ["JoinedPatternExpression$macrocall$1"], "postprocess": d => new JoinedPatternExpression(d[0])}, + {"name": "FunctionCallExpression$macrocall$2", "symbols": ["FunctionCallArgument"]}, + {"name": "FunctionCallExpression$macrocall$1$ebnf$1", "symbols": []}, + {"name": "FunctionCallExpression$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "FunctionCallExpression$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "FunctionCallExpression$macrocall$1$ebnf$1", "symbols": ["FunctionCallExpression$macrocall$1$ebnf$1", "FunctionCallExpression$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "FunctionCallExpression$macrocall$1", "symbols": ["FunctionCallExpression$macrocall$2", "FunctionCallExpression$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, "_?", "FunctionCallExpression$macrocall$1", "_?", {"literal":")"}], "postprocess": d => new FunctionCall(d[0], d[4])}, + {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, {"literal":")"}], "postprocess": d => new FunctionCall(d[0], [])}, + {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["PatternExpression"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new AnchorArgument(d[0])}, + {"name": "FunctionCallArgument", "symbols": [{"literal":"not"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanNot(d[2])}, + {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"and"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanAnd(d[0], d[4])}, + {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"or"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanOr(d[0], d[4])}, + {"name": "BeatGroupLiteral", "symbols": [{"literal":"<"}, "_?", "MeasureGroup", "_?", {"literal":">"}], "postprocess": d => new BeatGroupLiteral(d[2])}, + {"name": "MeasureGroup$macrocall$2", "symbols": ["Measure"]}, + {"name": "MeasureGroup$macrocall$3", "symbols": [{"literal":"|"}]}, + {"name": "MeasureGroup$macrocall$1$ebnf$1", "symbols": []}, + {"name": "MeasureGroup$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_?", "MeasureGroup$macrocall$3", "_?", "MeasureGroup$macrocall$2"], "postprocess": d => d[3][0]}, + {"name": "MeasureGroup$macrocall$1$ebnf$1", "symbols": ["MeasureGroup$macrocall$1$ebnf$1", "MeasureGroup$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "MeasureGroup$macrocall$1", "symbols": ["MeasureGroup$macrocall$2", "MeasureGroup$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "MeasureGroup", "symbols": ["MeasureGroup$macrocall$1"], "postprocess": id}, + {"name": "Measure$macrocall$2", "symbols": ["MelodicBeatLiteral"]}, + {"name": "Measure$macrocall$1$ebnf$1", "symbols": []}, + {"name": "Measure$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "Measure$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "Measure$macrocall$1$ebnf$1", "symbols": ["Measure$macrocall$1$ebnf$1", "Measure$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "Measure$macrocall$1", "symbols": ["Measure$macrocall$2", "Measure$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "Measure", "symbols": ["Measure$macrocall$1"], "postprocess": d => new Measure(d[0])}, + {"name": "MelodicBeatLiteral", "symbols": ["BL_TimePart", {"literal":":"}, "BL_PitchPart", {"literal":":"}, "BL_OctavePart"], "postprocess": d => new MelodicBeatLiteral({time: d[0], pitch: d[2], octave: d[4]})}, + {"name": "MelodicBeatLiteral", "symbols": [{"literal":":"}, "BL_PitchPart", {"literal":":"}, "BL_OctavePart"], "postprocess": d => new MelodicBeatLiteral({pitch: d[1], octave: d[3]})}, + {"name": "MelodicBeatLiteral", "symbols": ["BL_TimePart", {"literal":":"}, "BL_PitchPart"], "postprocess": d => new MelodicBeatLiteral({time: d[0], pitch: d[2]})}, + {"name": "MelodicBeatLiteral", "symbols": [{"literal":":"}, "BL_PitchPart"], "postprocess": d => new MelodicBeatLiteral({pitch: d[1]})}, + {"name": "MelodicBeatLiteral", "symbols": ["DrumBeatLiteral"], "postprocess": id}, + {"name": "BL_TimePart", "symbols": ["NumericExpression"], "postprocess": d => ({time: d[0]})}, + {"name": "BL_TimePart", "symbols": ["BL_TP_Flag"], "postprocess": d => ({time: 'auto', flag: d[0]})}, + {"name": "BL_TimePart", "symbols": ["NumericExpression", "BL_TP_Flag"], "postprocess": d => ({time: d[0], flag: d[1]})}, + {"name": "BL_TP_Flag", "symbols": [{"literal":"s"}], "postprocess": d => 'STACCATO'}, + {"name": "BL_TP_Flag", "symbols": [{"literal":"a"}], "postprocess": d => 'ACCENTED'}, + {"name": "BL_PitchPart", "symbols": ["BL_PP_Degree"], "postprocess": id}, + {"name": "BL_PitchPart", "symbols": ["BL_PP_Chord"], "postprocess": id}, + {"name": "BL_PP_Degree", "symbols": ["NumberLiteral"], "postprocess": d => ({degree: d[0]})}, + {"name": "BL_PP_Degree", "symbols": ["BL_PP_Anchor"], "postprocess": d => ({anchor: d[0], degree: 1})}, + {"name": "BL_PP_Degree", "symbols": ["BL_PP_Anchor", "NumberLiteral"], "postprocess": d => ({anchor: d[0], degree: d[1]})}, + {"name": "BL_PP_Chord", "symbols": [{"literal":"c"}], "postprocess": d => ({chord: true, degree: 1})}, + {"name": "BL_PP_Chord", "symbols": ["BL_PP_Degree", {"literal":"c"}], "postprocess": d => ({chord: true, anchor: d[0].anchor, degree: d[0].degree})}, + {"name": "BL_PP_Chord", "symbols": [{"literal":"c"}, "BL_PP_Roll"], "postprocess": d => ({chord: true, roll: d[1], degree: 1})}, + {"name": "BL_PP_Chord", "symbols": ["BL_PP_Degree", {"literal":"c"}, "BL_PP_Roll"], "postprocess": d => ({chord: true, roll: d[2], anchor: d[0].anchor, degree: d[0].degree})}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"k"}], "postprocess": d => 'KEY'}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"n"}], "postprocess": d => 'NEXT'}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"s"}], "postprocess": d => 'STEP'}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"a"}], "postprocess": d => 'ARPEGGIATE'}, + {"name": "BL_PP_Roll", "symbols": [{"literal":"r"}], "postprocess": d => 'ROLL_UP'}, + {"name": "BL_PP_Roll", "symbols": [{"literal":"r"}, {"literal":"d"}], "postprocess": d => 'ROLL_DOWN'}, + {"name": "BL_OctavePart", "symbols": ["NumberLiteral"], "postprocess": id}, + {"name": "DrumBeatGroupLiteral", "symbols": ["StringLiteral", "_?", "BeatGroupLiteral"], "postprocess": d => new DrumBeatGroupLiteral(d[0], d[2])}, + {"name": "DrumBeatGroupLiteral", "symbols": ["StringLiteral", "_?", "FunctionCallExpression"], "postprocess": d => new DrumBeatGroupLiteral(d[0], d[2])}, + {"name": "DrumBeatLiteral", "symbols": ["NumberLiteral"], "postprocess": d => new DrumBeatLiteral({time: d[0]})}, + {"name": "DrumBeatLiteral", "symbols": ["NumberLiteral", {"literal":"a"}], "postprocess": d => new DrumBeatLiteral({time: d[0], accented: true})}, + {"name": "NumericExpression", "symbols": ["NE_addsub"], "postprocess": id}, + {"name": "NE_parens", "symbols": [{"literal":"("}, "NE_addsub", {"literal":")"}], "postprocess": d => d[1]}, + {"name": "NE_parens", "symbols": ["NumberLiteral"], "postprocess": id}, + {"name": "NE_muldiv", "symbols": ["NE_muldiv", {"literal":"*"}, "NE_parens"], "postprocess": d => (d[0] * d[2])}, + {"name": "NE_muldiv", "symbols": ["NE_muldiv", {"literal":"/"}, "NE_parens"], "postprocess": d => (d[0] / d[2])}, + {"name": "NE_muldiv", "symbols": ["NE_parens"], "postprocess": id}, + {"name": "NE_addsub", "symbols": ["NE_addsub", {"literal":"+"}, "NE_muldiv"], "postprocess": d => (d[0] + d[2])}, + {"name": "NE_addsub", "symbols": ["NE_addsub", {"literal":"-"}, "NE_muldiv"], "postprocess": d => (d[0] - d[2])}, + {"name": "NE_addsub", "symbols": ["NE_muldiv"], "postprocess": id}, + {"name": "Identifier", "symbols": [(lexer.has("identifier") ? {type: "identifier"} : identifier)], "postprocess": d => d[0].value}, + {"name": "NumberLiteral", "symbols": [(lexer.has("number") ? {type: "number"} : number)], "postprocess": d => Number(d[0].value)}, + {"name": "NumberLiteral", "symbols": [(lexer.has("beat_number") ? {type: "beat_number"} : beat_number)], "postprocess": d => Number(d[0].value)}, + {"name": "BooleanLiteral", "symbols": [(lexer.has("boolean") ? {type: "boolean"} : boolean)], "postprocess": d => Boolean(d[0].value)}, + {"name": "StringLiteral", "symbols": [(lexer.has("quoted_string") ? {type: "quoted_string"} : quoted_string)], "postprocess": d => d[0].value.slice(1, -1)}, + {"name": "_?$ebnf$1", "symbols": ["_"], "postprocess": id}, + {"name": "_?$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_?", "symbols": ["_?$ebnf$1"], "postprocess": () => null}, + {"name": "_", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": () => null}, + {"name": "_", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": () => null}, + {"name": "_$ebnf$1", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": id}, + {"name": "_$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$2$subexpression$1$ebnf$1", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": id}, + {"name": "_$ebnf$2$subexpression$1$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$2$subexpression$1", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$2$subexpression$1$ebnf$1"]}, + {"name": "_$ebnf$2", "symbols": ["_$ebnf$2$subexpression$1"]}, + {"name": "_$ebnf$2$subexpression$2$ebnf$1", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": id}, + {"name": "_$ebnf$2$subexpression$2$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$2$subexpression$2", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$2$subexpression$2$ebnf$1"]}, + {"name": "_$ebnf$2", "symbols": ["_$ebnf$2", "_$ebnf$2$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "_", "symbols": ["_$ebnf$1", "_$ebnf$2"], "postprocess": () => null}, + {"name": "_$ebnf$3", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": id}, + {"name": "_$ebnf$3", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$4$subexpression$1$ebnf$1", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": id}, + {"name": "_$ebnf$4$subexpression$1$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$4$subexpression$1", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$4$subexpression$1$ebnf$1"]}, + {"name": "_$ebnf$4", "symbols": ["_$ebnf$4$subexpression$1"]}, + {"name": "_$ebnf$4$subexpression$2$ebnf$1", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": id}, + {"name": "_$ebnf$4$subexpression$2$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$4$subexpression$2", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$4$subexpression$2$ebnf$1"]}, + {"name": "_$ebnf$4", "symbols": ["_$ebnf$4", "_$ebnf$4$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "_", "symbols": ["_$ebnf$3", "_$ebnf$4"], "postprocess": () => null} +]; +let ParserStart = "main"; +var grammar = { Lexer, ParserRules, ParserStart }; + +/** + * Parses a string into a set of possible abstract systax trees (ASTs) trees of + * objects representing the syntax of the file. + * @param {string} data The string to parse + * @return {Promise..} A promise that resolves to an array + * of parsings, each of which is an AST. (Ideally there should be 1 parsing.) + * + * See ast_nodes.js or the grammar itself for an idea of what the nodes in the + * tree might look like. + * @private + */ +function getPossibleParses(data) { + return __awaiter(this, void 0, void 0, function* () { + // Create a Parser object from our grammar. + // (I don't think you can reset the parser so make a new one each time) + const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar)); + try { + parser.feed(data); + return parser.results; + } + catch (err) { + // Because tabs screw up the formatting of SyntaxError messages. + err.message = err.message.replace(/\t/g, ' '); + throw err; + } + }); +} +/** + * Parse a string into an Abstract Syntax Tree (AST) -- a tree of objects + * representing the syntax of the file. + * @param {string} data The string to parse + * @return {Promise.} The Abstract Systax Tree (AST). + */ +function parse(data) { + return __awaiter(this, void 0, void 0, function* () { + const parses = yield getPossibleParses(data); + if (!parses.length) { + throw new SyntaxError('Something went wrong, input not parseable.'); + } + return parses[0]; + }); +} + +class PlaybackStyle { + /** + * Set the main ast (the one that plays all its instruments by default). + * @param {ast.GlobalScope} main the main ast + * @param {Map.} asts A map of asts by their path + */ + constructor(mainPath) { + this.mainPath = mainPath; + this.ASTs = new Map(); + this.initialized = false; + } + /** + * Parse each file, pull its dependencies, put it all in a cache, rinse and + * repeat. + * @private + */ + _loadDependencies() { + return __awaiter(this, void 0, void 0, function* () { + let pendingDependencies = [this.mainPath]; + let dependencyPath; + // @TODO: verify that dependencies have compatible time signature to main + while (dependencyPath = pendingDependencies.pop()) { + let rawfile; + try { + rawfile = yield load(dependencyPath); + } + catch (e) { + throw new Error(`Couldn't locate imported style "${dependencyPath}".`); + } + let ast = yield parse(rawfile); + this.ASTs.set(dependencyPath, ast); + ast.init(); + for (let newDependency of ast.dependencies) { + if (!this.ASTs.has(newDependency)) { + pendingDependencies.push(newDependency); + } + } + } + this.main = this.ASTs.get(this.mainPath); + }); + } + _link() { + this.main.link(this.ASTs); + } + /** + * Initialize the style, which includes loading dependencies and linking + * track/pattern calls. Must be called before compiling/playing. + */ + init() { + return __awaiter(this, void 0, void 0, function* () { + yield this._loadDependencies(); + this._link(); + this.initialized = true; + }); + } + /** + * Compile a song into a set of MIDI-like note instructions. + * @param {Song} song A Playback Song (notochord????) + * @returns {NoteSet.} An array-like object containing MIDI-like note + * instructions. + */ + compile(song) { + if (!this.initialized) { + throw new Error('PlayBack style must be initialized before compiling'); + } + let songIterator = song[Symbol.iterator](); + let instruments = this.getInstruments(); + let notes = new Map(); + let beatsPerMeasure = this.main.vars.get('time-signature')[0]; + let totalPastBeats = 0; + for (let instrument of instruments) + notes.set(instrument, new NoteSet()); + let nextValue; + while (nextValue = songIterator.next(), nextValue.done == false) { + let thisMeasureTracks = this.main.execute(songIterator); + for (let [instrument, thisMeasureNotes] of thisMeasureTracks) { + for (let note of thisMeasureNotes) { + note.time += totalPastBeats; + if (this.main.vars.get('swing')) { + let int_part = Math.floor(note.time); + let float_part = note.time - int_part; + if (float_part <= 0.5) { + float_part *= 2; + float_part = (2 / 3) * float_part; + } + else { + float_part = 2 * (float_part - 0.5); + float_part = (2 / 3) + ((1 / 3) * float_part); + } + note.time = int_part + float_part; + } + } + notes.get(instrument).push(...thisMeasureNotes); + } + totalPastBeats += beatsPerMeasure; + } + return notes; + } + getInstruments() { + return this.main.getInstruments(); + } +} + +let moduleDefs = {1:[function(require,module,exports){ + + var load = require('audio-loader'); + var player = require('sample-player'); + + /** + * Load a soundfont instrument. It returns a promise that resolves to a + * instrument object. + * + * The instrument object returned by the promise has the following properties: + * + * - name: the instrument name + * - play: A function to play notes from the buffer with the signature + * `play(note, time, duration, options)` + * + * + * The valid options are: + * + * - `format`: the soundfont format. 'mp3' by default. Can be 'ogg' + * - `soundfont`: the soundfont name. 'MusyngKite' by default. Can be 'FluidR3_GM' + * - `nameToUrl` : a function to convert from instrument names to URL + * - `destination`: by default Soundfont uses the `audioContext.destination` but you can override it. + * - `gain`: the gain of the player (1 by default) + * - `notes`: an array of the notes to decode. It can be an array of strings + * with note names or an array of numbers with midi note numbers. This is a + * performance option: since decoding mp3 is a cpu intensive process, you can limit + * limit the number of notes you want and reduce the time to load the instrument. + * + * @param {AudioContext} ac - the audio context + * @param {String} name - the instrument name. For example: 'acoustic_grand_piano' + * @param {Object} options - (Optional) the same options as Soundfont.loadBuffers + * @return {Promise} + * + * @example + * var Soundfont = require('sounfont-player') + * Soundfont.instrument('marimba').then(function (marimba) { + * marimba.play('C4') + * }) + */ + function instrument (ac, name, options) { + if (arguments.length === 1) return function (n, o) { return instrument(ac, n, o) } + var opts = options || {}; + var isUrl = opts.isSoundfontURL || isSoundfontURL; + var toUrl = opts.nameToUrl || nameToUrl; + var url = isUrl(name) ? name : toUrl(name, opts.soundfont, opts.format); + + return load(ac, url, { only: opts.only || opts.notes }).then(function (buffers) { + var p = player(ac, buffers, opts).connect(opts.destination ? opts.destination : ac.destination); + p.url = url; + p.name = name; + return p + }) + } + + function isSoundfontURL (name) { + return /\.js(\?.*)?$/i.test(name) + } + + /** + * Given an instrument name returns a URL to to the Benjamin Gleitzman's + * package of [pre-rendered sound fonts](https://github.com/gleitz/midi-js-soundfonts) + * + * @param {String} name - instrument name + * @param {String} soundfont - (Optional) the soundfont name. One of 'FluidR3_GM' + * or 'MusyngKite' ('MusyngKite' by default) + * @param {String} format - (Optional) Can be 'mp3' or 'ogg' (mp3 by default) + * @returns {String} the Soundfont file url + * @example + * var Soundfont = require('soundfont-player') + * Soundfont.nameToUrl('marimba', 'mp3') + */ + function nameToUrl (name, sf, format) { + format = format === 'ogg' ? format : 'mp3'; + sf = sf === 'FluidR3_GM' ? sf : 'MusyngKite'; + return 'https://gleitz.github.io/midi-js-soundfonts/' + sf + '/' + name + '-' + format + '.js' + } + + // In the 1.0.0 release it will be: + // var Soundfont = {} + var Soundfont = require('./legacy'); + Soundfont.instrument = instrument; + Soundfont.nameToUrl = nameToUrl; + + if (typeof module === 'object' && module.exports) module.exports = Soundfont; + if (typeof window !== 'undefined') window.Soundfont = Soundfont; + + },{"./legacy":2,"audio-loader":6,"sample-player":10}],2:[function(require,module,exports){ + + var parser = require('note-parser'); + + /** + * Create a Soundfont object + * + * @param {AudioContext} context - the [audio context](https://developer.mozilla.org/en/docs/Web/API/AudioContext) + * @param {Function} nameToUrl - (Optional) a function that maps the sound font name to the url + * @return {Soundfont} a soundfont object + */ + function Soundfont (ctx, nameToUrl) { + console.warn('new Soundfont() is deprected'); + console.log('Please use Soundfont.instrument() instead of new Soundfont().instrument()'); + if (!(this instanceof Soundfont)) return new Soundfont(ctx) + + this.nameToUrl = nameToUrl || Soundfont.nameToUrl; + this.ctx = ctx; + this.instruments = {}; + this.promises = []; + } + + Soundfont.prototype.onready = function (callback) { + console.warn('deprecated API'); + console.log('Please use Promise.all(Soundfont.instrument(), Soundfont.instrument()).then() instead of new Soundfont().onready()'); + Promise.all(this.promises).then(callback); + }; + + Soundfont.prototype.instrument = function (name, options) { + console.warn('new Soundfont().instrument() is deprecated.'); + console.log('Please use Soundfont.instrument() instead.'); + var ctx = this.ctx; + name = name || 'default'; + if (name in this.instruments) return this.instruments[name] + var inst = {name: name, play: oscillatorPlayer(ctx, options)}; + this.instruments[name] = inst; + if (name !== 'default') { + var promise = Soundfont.instrument(ctx, name, options).then(function (instrument) { + inst.play = instrument.play; + return inst + }); + this.promises.push(promise); + inst.onready = function (cb) { + console.warn('onready is deprecated. Use Soundfont.instrument().then()'); + promise.then(cb); + }; + } else { + inst.onready = function (cb) { + console.warn('onready is deprecated. Use Soundfont.instrument().then()'); + cb(); + }; + } + return inst + }; + + /* + * Load the buffers of a given instrument name. It returns a promise that resolves + * to a hash with midi note numbers as keys, and audio buffers as values. + * + * @param {AudioContext} ac - the audio context + * @param {String} name - the instrument name (it accepts an url if starts with "http") + * @param {Object} options - (Optional) options object + * @return {Promise} a promise that resolves to a Hash of { midiNoteNum: } + * + * The options object accepts the following keys: + * + * - nameToUrl {Function}: a function to convert from instrument names to urls. + * By default it uses Benjamin Gleitzman's package of + * [pre-rendered sound fonts](https://github.com/gleitz/midi-js-soundfonts) + * - notes {Array}: the list of note names to be decoded (all by default) + * + * @example + * var Soundfont = require('soundfont-player') + * Soundfont.loadBuffers(ctx, 'acoustic_grand_piano').then(function(buffers) { + * buffers[60] // => An corresponding to note C4 + * }) + */ + function loadBuffers (ac, name, options) { + console.warn('Soundfont.loadBuffers is deprecate.'); + console.log('Use Soundfont.instrument(..) and get buffers properties from the result.'); + return Soundfont.instrument(ac, name, options).then(function (inst) { + return inst.buffers + }) + } + Soundfont.loadBuffers = loadBuffers; + + /** + * Returns a function that plays an oscillator + * + * @param {AudioContext} ac - the audio context + * @param {Hash} defaultOptions - (Optional) a hash of options: + * - vcoType: the oscillator type (default: 'sine') + * - gain: the output gain value (default: 0.4) + * - destination: the player destination (default: ac.destination) + */ + function oscillatorPlayer (ctx, defaultOptions) { + defaultOptions = defaultOptions || {}; + return function (note, time, duration, options) { + console.warn('The oscillator player is deprecated.'); + console.log('Starting with version 0.9.0 you will have to wait until the soundfont is loaded to play sounds.'); + var midi = note > 0 && note < 129 ? +note : parser.midi(note); + var freq = midi ? parser.midiToFreq(midi, 440) : null; + if (!freq) return + + duration = duration || 0.2; + + options = options || {}; + var destination = options.destination || defaultOptions.destination || ctx.destination; + var vcoType = options.vcoType || defaultOptions.vcoType || 'sine'; + var gain = options.gain || defaultOptions.gain || 0.4; + + var vco = ctx.createOscillator(); + vco.type = vcoType; + vco.frequency.value = freq; + + /* VCA */ + var vca = ctx.createGain(); + vca.gain.value = gain; + + /* Connections */ + vco.connect(vca); + vca.connect(destination); + + vco.start(time); + if (duration > 0) vco.stop(time + duration); + return vco + } + } + + /** + * Given a note name, return the note midi number + * + * @name noteToMidi + * @function + * @param {String} noteName + * @return {Integer} the note midi number or null if not a valid note name + */ + Soundfont.noteToMidi = parser.midi; + + module.exports = Soundfont; + + },{"note-parser":8}],3:[function(require,module,exports){ + module.exports = ADSR; + + function ADSR(audioContext){ + var node = audioContext.createGain(); + + var voltage = node._voltage = getVoltage(audioContext); + var value = scale(voltage); + var startValue = scale(voltage); + var endValue = scale(voltage); + + node._startAmount = scale(startValue); + node._endAmount = scale(endValue); + + node._multiplier = scale(value); + node._multiplier.connect(node); + node._startAmount.connect(node); + node._endAmount.connect(node); + + node.value = value.gain; + node.startValue = startValue.gain; + node.endValue = endValue.gain; + + node.startValue.value = 0; + node.endValue.value = 0; + + Object.defineProperties(node, props); + return node + } + + var props = { + + attack: { value: 0, writable: true }, + decay: { value: 0, writable: true }, + sustain: { value: 1, writable: true }, + release: {value: 0, writable: true }, + + getReleaseDuration: { + value: function(){ + return this.release + } + }, + + start: { + value: function(at){ + var target = this._multiplier.gain; + var startAmount = this._startAmount.gain; + var endAmount = this._endAmount.gain; + + this._voltage.start(at); + this._decayFrom = this._decayFrom = at+this.attack; + this._startedAt = at; + + var sustain = this.sustain; + + target.cancelScheduledValues(at); + startAmount.cancelScheduledValues(at); + endAmount.cancelScheduledValues(at); + + endAmount.setValueAtTime(0, at); + + if (this.attack){ + target.setValueAtTime(0, at); + target.linearRampToValueAtTime(1, at + this.attack); + + startAmount.setValueAtTime(1, at); + startAmount.linearRampToValueAtTime(0, at + this.attack); + } else { + target.setValueAtTime(1, at); + startAmount.setValueAtTime(0, at); + } + + if (this.decay){ + target.setTargetAtTime(sustain, this._decayFrom, getTimeConstant(this.decay)); + } + } + }, + + stop: { + value: function(at, isTarget){ + if (isTarget){ + at = at - this.release; + } + + var endTime = at + this.release; + if (this.release){ + + var target = this._multiplier.gain; + var startAmount = this._startAmount.gain; + var endAmount = this._endAmount.gain; + + target.cancelScheduledValues(at); + startAmount.cancelScheduledValues(at); + endAmount.cancelScheduledValues(at); + + var expFalloff = getTimeConstant(this.release); + + // truncate attack (required as linearRamp is removed by cancelScheduledValues) + if (this.attack && at < this._decayFrom){ + var valueAtTime = getValue(0, 1, this._startedAt, this._decayFrom, at); + target.linearRampToValueAtTime(valueAtTime, at); + startAmount.linearRampToValueAtTime(1-valueAtTime, at); + startAmount.setTargetAtTime(0, at, expFalloff); + } + + endAmount.setTargetAtTime(1, at, expFalloff); + target.setTargetAtTime(0, at, expFalloff); + } + + this._voltage.stop(endTime); + return endTime + } + }, + + onended: { + get: function(){ + return this._voltage.onended + }, + set: function(value){ + this._voltage.onended = value; + } + } + + }; + + var flat = new Float32Array([1,1]); + function getVoltage(context){ + var voltage = context.createBufferSource(); + var buffer = context.createBuffer(1, 2, context.sampleRate); + buffer.getChannelData(0).set(flat); + voltage.buffer = buffer; + voltage.loop = true; + return voltage + } + + function scale(node){ + var gain = node.context.createGain(); + node.connect(gain); + return gain + } + + function getTimeConstant(time){ + return Math.log(time+1)/Math.log(100) + } + + function getValue(start, end, fromTime, toTime, at){ + var difference = end - start; + var time = toTime - fromTime; + var truncateTime = at - fromTime; + var phase = truncateTime / time; + var value = start + phase * difference; + + if (value <= start) { + value = start; + } + if (value >= end) { + value = end; + } + + return value + } + + },{}],4:[function(require,module,exports){ + + // DECODE UTILITIES + function b64ToUint6 (nChr) { + return nChr > 64 && nChr < 91 ? nChr - 65 + : nChr > 96 && nChr < 123 ? nChr - 71 + : nChr > 47 && nChr < 58 ? nChr + 4 + : nChr === 43 ? 62 + : nChr === 47 ? 63 + : 0 + } + + // Decode Base64 to Uint8Array + // --------------------------- + function decode (sBase64, nBlocksSize) { + var sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ''); + var nInLen = sB64Enc.length; + var nOutLen = nBlocksSize + ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize + : nInLen * 3 + 1 >> 2; + var taBytes = new Uint8Array(nOutLen); + + for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) { + nMod4 = nInIdx & 3; + nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4; + if (nMod4 === 3 || nInLen - nInIdx === 1) { + for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) { + taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255; + } + nUint24 = 0; + } + } + return taBytes + } + + module.exports = { decode: decode }; + + },{}],5:[function(require,module,exports){ + + /** + * Given a url and a return type, returns a promise to the content of the url + * Basically it wraps a XMLHttpRequest into a Promise + * + * @param {String} url + * @param {String} type - can be 'text' or 'arraybuffer' + * @return {Promise} + */ + module.exports = function (url, type) { + return new Promise(function (done, reject) { + var req = new XMLHttpRequest(); + if (type) req.responseType = type; + + req.open('GET', url); + req.onload = function () { + req.status === 200 ? done(req.response) : reject(Error(req.statusText)); + }; + req.onerror = function () { reject(Error('Network Error')); }; + req.send(); + }) + }; + + },{}],6:[function(require,module,exports){ + + var base64 = require('./base64'); + var fetch = require('./fetch'); + + // Given a regex, return a function that test if against a string + function fromRegex (r) { + return function (o) { return typeof o === 'string' && r.test(o) } + } + // Try to apply a prefix to a name + function prefix (pre, name) { + return typeof pre === 'string' ? pre + name + : typeof pre === 'function' ? pre(name) + : name + } + + /** + * Load one or more audio files + * + * + * Possible option keys: + * + * - __from__ {Function|String}: a function or string to convert from file names to urls. + * If is a string it will be prefixed to the name: + * `load(ac, 'snare.mp3', { from: 'http://audio.net/samples/' })` + * If it's a function it receives the file name and should return the url as string. + * - __only__ {Array} - when loading objects, if provided, only the given keys + * will be included in the decoded object: + * `load(ac, 'piano.json', { only: ['C2', 'D2'] })` + * + * @param {AudioContext} ac - the audio context + * @param {Object} source - the object to be loaded + * @param {Object} options - (Optional) the load options for that object + * @param {Object} defaultValue - (Optional) the default value to return as + * in a promise if not valid loader found + */ + function load (ac, source, options, defVal) { + var loader = + // Basic audio loading + isArrayBuffer(source) ? loadArrayBuffer + : isAudioFileName(source) ? loadAudioFile + : isPromise(source) ? loadPromise + // Compound objects + : isArray(source) ? loadArrayData + : isObject(source) ? loadObjectData + : isJsonFileName(source) ? loadJsonFile + // Base64 encoded audio + : isBase64Audio(source) ? loadBase64Audio + : isJsFileName(source) ? loadMidiJSFile + : null; + + var opts = options || {}; + return loader ? loader(ac, source, opts) + : defVal ? Promise.resolve(defVal) + : Promise.reject('Source not valid (' + source + ')') + } + load.fetch = fetch; + + // BASIC AUDIO LOADING + // =================== + + // Load (decode) an array buffer + function isArrayBuffer (o) { return o instanceof ArrayBuffer } + function loadArrayBuffer (ac, array, options) { + return new Promise(function (done, reject) { + ac.decodeAudioData(array, + function (buffer) { done(buffer); }, + function () { reject("Can't decode audio data (" + array.slice(0, 30) + '...)'); } + ); + }) + } + + // Load an audio filename + var isAudioFileName = fromRegex(/\.(mp3|wav|ogg)(\?.*)?$/i); + function loadAudioFile (ac, name, options) { + var url = prefix(options.from, name); + return load(ac, load.fetch(url, 'arraybuffer'), options) + } + + // Load the result of a promise + function isPromise (o) { return o && typeof o.then === 'function' } + function loadPromise (ac, promise, options) { + return promise.then(function (value) { + return load(ac, value, options) + }) + } + + // COMPOUND OBJECTS + // ================ + + // Try to load all the items of an array + var isArray = Array.isArray; + function loadArrayData (ac, array, options) { + return Promise.all(array.map(function (data) { + return load(ac, data, options, data) + })) + } + + // Try to load all the values of a key/value object + function isObject (o) { return o && typeof o === 'object' } + function loadObjectData (ac, obj, options) { + var dest = {}; + var promises = Object.keys(obj).map(function (key) { + if (options.only && options.only.indexOf(key) === -1) return null + var value = obj[key]; + return load(ac, value, options, value).then(function (audio) { + dest[key] = audio; + }) + }); + return Promise.all(promises).then(function () { return dest }) + } + + // Load the content of a JSON file + var isJsonFileName = fromRegex(/\.json(\?.*)?$/i); + function loadJsonFile (ac, name, options) { + var url = prefix(options.from, name); + return load(ac, load.fetch(url, 'text').then(JSON.parse), options) + } + + // BASE64 ENCODED FORMATS + // ====================== + + // Load strings with Base64 encoded audio + var isBase64Audio = fromRegex(/^data:audio/); + function loadBase64Audio (ac, source, options) { + var i = source.indexOf(','); + return load(ac, base64.decode(source.slice(i + 1)).buffer, options) + } + + // Load .js files with MidiJS soundfont prerendered audio + var isJsFileName = fromRegex(/\.js(\?.*)?$/i); + function loadMidiJSFile (ac, name, options) { + var url = prefix(options.from, name); + return load(ac, load.fetch(url, 'text').then(midiJsToJson), options) + } + + // convert a MIDI.js javascript soundfont file to json + function midiJsToJson (data) { + var begin = data.indexOf('MIDI.Soundfont.'); + if (begin < 0) throw Error('Invalid MIDI.js Soundfont format') + begin = data.indexOf('=', begin) + 2; + var end = data.lastIndexOf(','); + return JSON.parse(data.slice(begin, end) + '}') + } + + if (typeof module === 'object' && module.exports) module.exports = load; + if (typeof window !== 'undefined') window.loadAudio = load; + + },{"./base64":4,"./fetch":5}],7:[function(require,module,exports){ + (function (global){ + (function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e();}else if(typeof define==="function"&&define.amd){define([],e);}else{var t;if(typeof window!=="undefined"){t=window;}else if(typeof global!=="undefined"){t=global;}else if(typeof self!=="undefined"){t=self;}else{t=this;}t.midimessage=e();}})(function(){return function o(e,t,s){function a(n,i){if(!t[n]){if(!e[n]){var l=typeof require=="function"&&require;if(!i&&l)return l(n,!0);if(r)return r(n,!0);var h=new Error("Cannot find module '"+n+"'");throw h.code="MODULE_NOT_FOUND",h}var c=t[n]={exports:{}};e[n][0].call(c.exports,function(t){var s=e[n][1][t];return a(s?s:t)},c,c.exports,o,e,t,s);}return t[n].exports}var r=typeof require=="function"&&require;for(var n=0;n6?null:C.charAt(t)+f(n)+a(r)}function p(t){if((r(t)||e(t))&&t>=0&&t<128)return +t;var n=i(t);return n&&u(n.midi)?n.midi:null}function s(t,n){var r=p(t);return null===r?null:c(r,n)}function d(t){return (i(t)||{}).letter}function m(t){return (i(t)||{}).acc}function h(t){return (i(t)||{}).pc}function v(t){return (i(t)||{}).step}function g(t){return (i(t)||{}).alt}function x(t){return (i(t)||{}).chroma}function y(t){return (i(t)||{}).oct}var b=/^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)\s*$/,A=[0,2,4,5,7,9,11],C="CDEFGAB";t.regex=o,t.parse=i,t.build=l,t.midi=p,t.freq=s,t.letter=d,t.acc=m,t.pc=h,t.step=v,t.alt=g,t.chroma=x,t.oct=y;}); + + + },{}],9:[function(require,module,exports){ + + module.exports = function (player) { + /** + * Adds a listener of an event + * @chainable + * @param {String} event - the event name + * @param {Function} callback - the event handler + * @return {SamplePlayer} the player + * @example + * player.on('start', function(time, note) { + * console.log(time, note) + * }) + */ + player.on = function (event, cb) { + if (arguments.length === 1 && typeof event === 'function') return player.on('event', event) + var prop = 'on' + event; + var old = player[prop]; + player[prop] = old ? chain(old, cb) : cb; + return player + }; + return player + }; + + function chain (fn1, fn2) { + return function (a, b, c, d) { fn1(a, b, c, d); fn2(a, b, c, d); } + } + + },{}],10:[function(require,module,exports){ + + var player = require('./player'); + var events = require('./events'); + var notes = require('./notes'); + var scheduler = require('./scheduler'); + var midi = require('./midi'); + + function SamplePlayer (ac, source, options) { + return midi(scheduler(notes(events(player(ac, source, options))))) + } + + if (typeof module === 'object' && module.exports) module.exports = SamplePlayer; + if (typeof window !== 'undefined') window.SamplePlayer = SamplePlayer; + + },{"./events":9,"./midi":11,"./notes":12,"./player":13,"./scheduler":14}],11:[function(require,module,exports){ + var midimessage = require('midimessage'); + + module.exports = function (player) { + /** + * Connect a player to a midi input + * + * The options accepts: + * + * - channel: the channel to listen to. Listen to all channels by default. + * + * @param {MIDIInput} input + * @param {Object} options - (Optional) + * @return {SamplePlayer} the player + * @example + * var piano = player(...) + * window.navigator.requestMIDIAccess().then(function (midiAccess) { + * midiAccess.inputs.forEach(function (midiInput) { + * piano.listenToMidi(midiInput) + * }) + * }) + */ + player.listenToMidi = function (input, options) { + var started = {}; + var opts = options || {}; + var gain = opts.gain || function (vel) { return vel / 127 }; + + input.onmidimessage = function (msg) { + var mm = msg.messageType ? msg : midimessage(msg); + if (mm.messageType === 'noteon' && mm.velocity === 0) { + mm.messageType = 'noteoff'; + } + if (opts.channel && mm.channel !== opts.channel) return + + switch (mm.messageType) { + case 'noteon': + started[mm.key] = player.play(mm.key, 0, { gain: gain(mm.velocity) }); + break + case 'noteoff': + if (started[mm.key]) { + started[mm.key].stop(); + delete started[mm.key]; + } + break + } + }; + return player + }; + return player + }; + + },{"midimessage":7}],12:[function(require,module,exports){ + + var note = require('note-parser'); + var isMidi = function (n) { return n !== null && n !== [] && n >= 0 && n < 129 }; + var toMidi = function (n) { return isMidi(n) ? +n : note.midi(n) }; + + // Adds note name to midi conversion + module.exports = function (player) { + if (player.buffers) { + var map = player.opts.map; + var toKey = typeof map === 'function' ? map : toMidi; + var mapper = function (name) { + return name ? toKey(name) || name : null + }; + + player.buffers = mapBuffers(player.buffers, mapper); + var start = player.start; + player.start = function (name, when, options) { + var key = mapper(name); + var dec = key % 1; + if (dec) { + key = Math.floor(key); + options = Object.assign(options || {}, { cents: Math.floor(dec * 100) }); + } + return start(key, when, options) + }; + } + return player + }; + + function mapBuffers (buffers, toKey) { + return Object.keys(buffers).reduce(function (mapped, name) { + mapped[toKey(name)] = buffers[name]; + return mapped + }, {}) + } + + },{"note-parser":15}],13:[function(require,module,exports){ + + var ADSR = require('adsr'); + + var EMPTY = {}; + var DEFAULTS = { + gain: 1, + attack: 0.01, + decay: 0.1, + sustain: 0.9, + release: 0.3, + loop: false, + cents: 0, + loopStart: 0, + loopEnd: 0 + }; + + /** + * Create a sample player. + * + * @param {AudioContext} ac - the audio context + * @param {ArrayBuffer|Object} source + * @param {Onject} options - (Optional) an options object + * @return {player} the player + * @example + * var SamplePlayer = require('sample-player') + * var ac = new AudioContext() + * var snare = SamplePlayer(ac, ) + * snare.play() + */ + function SamplePlayer (ac, source, options) { + var connected = false; + var nextId = 0; + var tracked = {}; + var out = ac.createGain(); + out.gain.value = 1; + + var opts = Object.assign({}, DEFAULTS, options); + + /** + * @namespace + */ + var player = { context: ac, out: out, opts: opts }; + if (source instanceof AudioBuffer) player.buffer = source; + else player.buffers = source; + + /** + * Start a sample buffer. + * + * The returned object has a function `stop(when)` to stop the sound. + * + * @param {String} name - the name of the buffer. If the source of the + * SamplePlayer is one sample buffer, this parameter is not required + * @param {Float} when - (Optional) when to start (current time if by default) + * @param {Object} options - additional sample playing options + * @return {AudioNode} an audio node with a `stop` function + * @example + * var sample = player(ac, ).connect(ac.destination) + * sample.start() + * sample.start(5, { gain: 0.7 }) // name not required since is only one AudioBuffer + * @example + * var drums = player(ac, { snare: , kick: , ... }).connect(ac.destination) + * drums.start('snare') + * drums.start('snare', 0, { gain: 0.3 }) + */ + player.start = function (name, when, options) { + // if only one buffer, reorder arguments + if (player.buffer && name !== null) return player.start(null, name, when) + + var buffer = name ? player.buffers[name] : player.buffer; + if (!buffer) { + console.warn('Buffer ' + name + ' not found.'); + return + } else if (!connected) { + console.warn('SamplePlayer not connected to any node.'); + return + } + + var opts = options || EMPTY; + when = Math.max(ac.currentTime, when || 0); + player.emit('start', when, name, opts); + var node = createNode(name, buffer, opts); + node.id = track(name, node); + node.env.start(when); + node.source.start(when); + player.emit('started', when, node.id, node); + if (opts.duration) node.stop(when + opts.duration); + return node + }; + + // NOTE: start will be override so we can't copy the function reference + // this is obviously not a good design, so this code will be gone soon. + /** + * An alias for `player.start` + * @see player.start + * @since 0.3.0 + */ + player.play = function (name, when, options) { + return player.start(name, when, options) + }; + + /** + * Stop some or all samples + * + * @param {Float} when - (Optional) an absolute time in seconds (or currentTime + * if not specified) + * @param {Array} nodes - (Optional) an array of nodes or nodes ids to stop + * @return {Array} an array of ids of the stoped samples + * + * @example + * var longSound = player(ac, ).connect(ac.destination) + * longSound.start(ac.currentTime) + * longSound.start(ac.currentTime + 1) + * longSound.start(ac.currentTime + 2) + * longSound.stop(ac.currentTime + 3) // stop the three sounds + */ + player.stop = function (when, ids) { + var node; + ids = ids || Object.keys(tracked); + return ids.map(function (id) { + node = tracked[id]; + if (!node) return null + node.stop(when); + return node.id + }) + }; + /** + * Connect the player to a destination node + * + * @param {AudioNode} destination - the destination node + * @return {AudioPlayer} the player + * @chainable + * @example + * var sample = player(ac, ).connect(ac.destination) + */ + player.connect = function (dest) { + connected = true; + out.connect(dest); + return player + }; + + player.emit = function (event, when, obj, opts) { + if (player.onevent) player.onevent(event, when, obj, opts); + var fn = player['on' + event]; + if (fn) fn(when, obj, opts); + }; + + return player + + // =============== PRIVATE FUNCTIONS ============== // + + function track (name, node) { + node.id = nextId++; + tracked[node.id] = node; + node.source.onended = function () { + var now = ac.currentTime; + node.source.disconnect(); + node.env.disconnect(); + node.disconnect(); + player.emit('ended', now, node.id, node); + }; + return node.id + } + + function createNode (name, buffer, options) { + var node = ac.createGain(); + node.gain.value = 0; // the envelope will control the gain + node.connect(out); + + node.env = envelope(ac, options, opts); + node.env.connect(node.gain); + + node.source = ac.createBufferSource(); + node.source.buffer = buffer; + node.source.connect(node); + node.source.loop = options.loop || opts.loop; + node.source.playbackRate.value = centsToRate(options.cents || opts.cents); + node.source.loopStart = options.loopStart || opts.loopStart; + node.source.loopEnd = options.loopEnd || opts.loopEnd; + node.stop = function (when) { + var time = when || ac.currentTime; + player.emit('stop', time, name); + var stopAt = node.env.stop(time); + node.source.stop(stopAt); + }; + return node + } + } + + function isNum (x) { return typeof x === 'number' } + var PARAMS = ['attack', 'decay', 'sustain', 'release']; + function envelope (ac, options, opts) { + var env = ADSR(ac); + var adsr = options.adsr || opts.adsr; + PARAMS.forEach(function (name, i) { + if (adsr) env[name] = adsr[i]; + else env[name] = options[name] || opts[name]; + }); + env.value.value = isNum(options.gain) ? options.gain + : isNum(opts.gain) ? opts.gain : 1; + return env + } + + /* + * Get playback rate for a given pitch change (in cents) + * Basic [math](http://www.birdsoft.demon.co.uk/music/samplert.htm): + * f2 = f1 * 2^( C / 1200 ) + */ + function centsToRate (cents) { return cents ? Math.pow(2, cents / 1200) : 1 } + + module.exports = SamplePlayer; + + },{"adsr":3}],14:[function(require,module,exports){ + + var isArr = Array.isArray; + var isObj = function (o) { return o && typeof o === 'object' }; + var OPTS = {}; + + module.exports = function (player) { + /** + * Schedule a list of events to be played at specific time. + * + * It supports three formats of events for the events list: + * + * - An array with [time, note] + * - An array with [time, object] + * - An object with { time: ?, [name|note|midi|key]: ? } + * + * @param {Float} time - an absolute time to start (or AudioContext's + * currentTime if provided number is 0) + * @param {Array} events - the events list. + * @return {Array} an array of ids + * + * @example + * // Event format: [time, note] + * var piano = player(ac, ...).connect(ac.destination) + * piano.schedule(0, [ [0, 'C2'], [0.5, 'C3'], [1, 'C4'] ]) + * + * @example + * // Event format: an object { time: ?, name: ? } + * var drums = player(ac, ...).connect(ac.destination) + * drums.schedule(0, [ + * { name: 'kick', time: 0 }, + * { name: 'snare', time: 0.5 }, + * { name: 'kick', time: 1 }, + * { name: 'snare', time: 1.5 } + * ]) + */ + player.schedule = function (time, events) { + var now = player.context.currentTime; + var when = time < now ? now : time; + player.emit('schedule', when, events); + var t, o, note, opts; + return events.map(function (event) { + if (!event) return null + else if (isArr(event)) { + t = event[0]; o = event[1]; + } else { + t = event.time; o = event; + } + + if (isObj(o)) { + note = o.name || o.key || o.note || o.midi || null; + opts = o; + } else { + note = o; + opts = OPTS; + } + + return player.start(note, when + (t || 0), opts) + }) + }; + return player + }; + + },{}],15:[function(require,module,exports){ + + var REGEX = /^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)\s*$/; + /** + * A regex for matching note strings in scientific notation. + * + * @name regex + * @function + * @return {RegExp} the regexp used to parse the note name + * + * The note string should have the form `letter[accidentals][octave][element]` + * where: + * + * - letter: (Required) is a letter from A to G either upper or lower case + * - accidentals: (Optional) can be one or more `b` (flats), `#` (sharps) or `x` (double sharps). + * They can NOT be mixed. + * - octave: (Optional) a positive or negative integer + * - element: (Optional) additionally anything after the duration is considered to + * be the element name (for example: 'C2 dorian') + * + * The executed regex contains (by array index): + * + * - 0: the complete string + * - 1: the note letter + * - 2: the optional accidentals + * - 3: the optional octave + * - 4: the rest of the string (trimmed) + * + * @example + * var parser = require('note-parser') + * parser.regex.exec('c#4') + * // => ['c#4', 'c', '#', '4', ''] + * parser.regex.exec('c#4 major') + * // => ['c#4major', 'c', '#', '4', 'major'] + * parser.regex().exec('CMaj7') + * // => ['CMaj7', 'C', '', '', 'Maj7'] + */ + function regex () { return REGEX } + + var SEMITONES = [0, 2, 4, 5, 7, 9, 11]; + /** + * Parse a note name in scientific notation an return it's components, + * and some numeric properties including midi number and frequency. + * + * @name parse + * @function + * @param {String} note - the note string to be parsed + * @param {Boolean} isTonic - true if the note is the tonic of something. + * If true, en extra tonicOf property is returned. It's false by default. + * @param {Float} tunning - The frequency of A4 note to calculate frequencies. + * By default it 440. + * @return {Object} the parsed note name or null if not a valid note + * + * The parsed note name object will ALWAYS contains: + * - letter: the uppercase letter of the note + * - acc: the accidentals of the note (only sharps or flats) + * - pc: the pitch class (letter + acc) + * - step: s a numeric representation of the letter. It's an integer from 0 to 6 + * where 0 = C, 1 = D ... 6 = B + * - alt: a numeric representation of the accidentals. 0 means no alteration, + * positive numbers are for sharps and negative for flats + * - chroma: a numeric representation of the pitch class. It's like midi for + * pitch classes. 0 = C, 1 = C#, 2 = D ... It can have negative values: -1 = Cb. + * Can detect pitch class enhramonics. + * + * If the note has octave, the parser object will contain: + * - oct: the octave number (as integer) + * - midi: the midi number + * - freq: the frequency (using tuning parameter as base) + * + * If the parameter `isTonic` is set to true, the parsed object will contain: + * - tonicOf: the rest of the string that follows note name (left and right trimmed) + * + * @example + * var parse = require('note-parser').parse + * parse('Cb4') + * // => { letter: 'C', acc: 'b', pc: 'Cb', step: 0, alt: -1, chroma: -1, + * oct: 4, midi: 59, freq: 246.94165062806206 } + * // if no octave, no midi, no freq + * parse('fx') + * // => { letter: 'F', acc: '##', pc: 'F##', step: 3, alt: 2, chroma: 7 }) + */ + function parse (str, isTonic, tuning) { + if (typeof str !== 'string') return null + var m = REGEX.exec(str); + if (!m || !isTonic && m[4]) return null + + var p = { letter: m[1].toUpperCase(), acc: m[2].replace(/x/g, '##') }; + p.pc = p.letter + p.acc; + p.step = (p.letter.charCodeAt(0) + 3) % 7; + p.alt = p.acc[0] === 'b' ? -p.acc.length : p.acc.length; + p.chroma = SEMITONES[p.step] + p.alt; + if (m[3]) { + p.oct = +m[3]; + p.midi = p.chroma + 12 * (p.oct + 1); + p.freq = midiToFreq(p.midi, tuning); + } + if (isTonic) p.tonicOf = m[4]; + return p + } + + /** + * Given a midi number, return its frequency + * @param {Integer} midi - midi note number + * @param {Float} tuning - (Optional) the A4 tuning (440Hz by default) + * @return {Float} frequency in hertzs + */ + function midiToFreq (midi, tuning) { + return Math.pow(2, (midi - 69) / 12) * (tuning || 440) + } + + var parser = { parse: parse, regex: regex, midiToFreq: midiToFreq }; + var FNS = ['letter', 'acc', 'pc', 'step', 'alt', 'chroma', 'oct', 'midi', 'freq']; + FNS.forEach(function (name) { + parser[name] = function (src) { + var p = parse(src); + return p && (typeof p[name] !== 'undefined') ? p[name] : null + }; + }); + + module.exports = parser; + + // extra API docs + /** + * Get midi of a note + * + * @name midi + * @function + * @param {String} note - the note name + * @return {Integer} the midi number of the note or null if not a valid note + * or the note does NOT contains octave + * @example + * var parser = require('note-parser') + * parser.midi('A4') // => 69 + * parser.midi('A') // => null + */ + /** + * Get freq of a note in hertzs (in a well tempered 440Hz A4) + * + * @name freq + * @function + * @param {String} note - the note name + * @return {Float} the freq of the number if hertzs or null if not valid note + * or the note does NOT contains octave + * @example + * var parser = require('note-parser') + * parser.freq('A4') // => 440 + * parser.freq('A') // => null + */ + + },{}]}; + +let modulesByID = {}; +function link(id) { + if(!modulesByID[id]) { + let _module = modulesByID[id] = { exports: {} }; + let _require = function(requiredName) { + let requiredID = moduleDefs[id][1][requiredName]; + return link(requiredID || requiredName); + }; + moduleDefs[id][0].call(_module.exports, _require, _module, _module.exports); + } + return modulesByID[id].exports; +} + +let soundfont = link(1); + +class Player { + /** + * Loads the necessary soundfonts and plays a song in a PlaybackStyle in the + * browser. + * @param {AudioContext=} context If you pass it an AudioContext it'll use + * it. Otherwise it'll make its own. + */ + constructor(context) { + this.style = null; + this.context = context || new AudioContext({ latencyHint: "playback" }); + this.initialized = false; + window.player = this; + } + setStyle(style) { + return __awaiter(this, void 0, void 0, function* () { + this.style = style; + if (!style._initialized) { + yield style.init(); + } + this.initialized = false; + this.soundfonts = new Map(); + let promises = []; + for (let instrument of style.getInstruments()) { + let sfpromise; + if (instrument.startsWith('http://') || instrument.startsWith('https://')) { + // Soundfont has a bug where you can't just pass it a URL + // @TODO: open an issue there + sfpromise = soundfont.instrument(this.context, instrument, { + isSoundfontUrl: () => true, + nameToUrl: () => instrument + }); + } + else if (instrument == 'percussion') { + sfpromise = soundfont.instrument(this.context, instrument, { soundfont: 'FluidR3_GM' }); + } + else { + sfpromise = soundfont.instrument(this.context, instrument); + } + promises.push(yield sfpromise.then(font => { + this.soundfonts.set(instrument, font); + })); + } + yield Promise.all(promises); + this.initialized = true; + }); + } + play(song) { + if (!this.style) { + throw new Error('No style selected'); + } + if (!this.initialized) { + throw new Error('A style hasn\'t finished loading'); + } + if (this.context.state == 'suspended') { + this.context.resume(); + } + let compiledSong = this.style.compile(song); + let tempoCoef = 0.4; // WHATEVER IDC HOW ANYTHING WORKS + let startTime = this.context.currentTime + 1; + for (let [instrument, notes] of compiledSong) { + let soundfont = this.soundfonts.get(instrument); + for (let note of notes) { + let start = startTime + (tempoCoef * note.time); + let dur = tempoCoef * note.duration - 0.05; + soundfont.play(note.midi, start, { + duration: dur, + gain: note.volume + }); + } + } + } +} + +exports.PlaybackStyle = PlaybackStyle; +exports.Player = Player; diff --git a/dist/playback.node.mjs b/dist/playback.node.mjs new file mode 100644 index 0000000..1849da6 --- /dev/null +++ b/dist/playback.node.mjs @@ -0,0 +1,3930 @@ +/** + * playback by Jacob Bloom + * This software is provided as-is, yadda yadda yadda + */ + +import * as _Tonal from 'tonal'; +import _Tonal__default, { } from 'tonal'; + +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + +function __awaiter(thisArg, _arguments, P, generator) { + 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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +/** + * Load a file. + * + * * Style locator algorithm: + * 1. If the path begins with http:// or https://, look at that URL + * 2. If the path begins with . or / look in the filesystem or at a relative URL + * 3. Otherwise, look in the styles folder in this repo (which will move to its + * own repo eventually). For these built-in styles, the .play file extension + * is not required. + * + * @param {string} path The path to the file to load. + * @return {string} The content of the file. + */ +function load(stylePath) { + return __awaiter(this, void 0, void 0, function* () { + let isHTTP = stylePath.startsWith('http://') || stylePath.startsWith('https://'); + let isRelative = stylePath.startsWith('.') || stylePath.startsWith('/'); + if (typeof process === 'undefined') { + if (isHTTP || isRelative) { + return fetch(stylePath).then(r => r.text()); + } + else { + let modulePath = ''; //String(import.meta.url).replace(/[^\/]+$/, ''); + stylePath = modulePath + '../../styles/' + stylePath; + if (!stylePath.endsWith('.play')) + stylePath += '.play'; + return fetch(stylePath).then(r => r.text()); + } + } + else { + if (isHTTP) { + const http = yield import(stylePath.startsWith('https://') ? 'https' : 'http'); + return new Promise((resolve, reject) => { + http.get(stylePath, res => { + let body = ''; + res.setEncoding('utf8'); + res.on('data', data => body += data); + res.on('end', () => resolve(body)); + res.on('error', reject); + }); + }); + } + if (!isRelative) { + let path = yield import('path'); + try { + stylePath = path.join(__dirname, '../../styles/', stylePath); + } + catch (_a) { } + if (!stylePath.endsWith('.play')) + stylePath += '.play'; + } + let fs = yield import('fs'); + return (new Promise((resolve, reject) => { + fs.readFile(stylePath, 'utf8', (err, data) => { + if (err) { + reject(err); + } + else { + resolve(data); + } + }); + })); + } + }); +} + +var nearley = (function() { + + function Rule(name, symbols, postprocess) { + this.id = ++Rule.highestId; + this.name = name; + this.symbols = symbols; // a list of literal | regex class | nonterminal + this.postprocess = postprocess; + return this; + } + Rule.highestId = 0; + + Rule.prototype.toString = function(withCursorAt) { + function stringifySymbolSequence (e) { + return e.literal ? JSON.stringify(e.literal) : + e.type ? '%' + e.type : e.toString(); + } + var symbolSequence = (typeof withCursorAt === "undefined") + ? this.symbols.map(stringifySymbolSequence).join(' ') + : ( this.symbols.slice(0, withCursorAt).map(stringifySymbolSequence).join(' ') + + " ● " + + this.symbols.slice(withCursorAt).map(stringifySymbolSequence).join(' ') ); + return this.name + " → " + symbolSequence; + }; + + + // a State is a rule at a position from a given starting point in the input stream (reference) + function State(rule, dot, reference, wantedBy) { + this.rule = rule; + this.dot = dot; + this.reference = reference; + this.data = []; + this.wantedBy = wantedBy; + this.isComplete = this.dot === rule.symbols.length; + } + + State.prototype.toString = function() { + return "{" + this.rule.toString(this.dot) + "}, from: " + (this.reference || 0); + }; + + State.prototype.nextState = function(child) { + var state = new State(this.rule, this.dot + 1, this.reference, this.wantedBy); + state.left = this; + state.right = child; + if (state.isComplete) { + state.data = state.build(); + } + return state; + }; + + State.prototype.build = function() { + var children = []; + var node = this; + do { + children.push(node.right.data); + node = node.left; + } while (node.left); + children.reverse(); + return children; + }; + + State.prototype.finish = function() { + if (this.rule.postprocess) { + this.data = this.rule.postprocess(this.data, this.reference, Parser.fail); + } + }; + + + function Column(grammar, index) { + this.grammar = grammar; + this.index = index; + this.states = []; + this.wants = {}; // states indexed by the non-terminal they expect + this.scannable = []; // list of states that expect a token + this.completed = {}; // states that are nullable + } + + + Column.prototype.process = function(nextColumn) { + var states = this.states; + var wants = this.wants; + var completed = this.completed; + + for (var w = 0; w < states.length; w++) { // nb. we push() during iteration + var state = states[w]; + + if (state.isComplete) { + state.finish(); + if (state.data !== Parser.fail) { + // complete + var wantedBy = state.wantedBy; + for (var i = wantedBy.length; i--; ) { // this line is hot + var left = wantedBy[i]; + this.complete(left, state); + } + + // special-case nullables + if (state.reference === this.index) { + // make sure future predictors of this rule get completed. + var exp = state.rule.name; + (this.completed[exp] = this.completed[exp] || []).push(state); + } + } + + } else { + // queue scannable states + var exp = state.rule.symbols[state.dot]; + if (typeof exp !== 'string') { + this.scannable.push(state); + continue; + } + + // predict + if (wants[exp]) { + wants[exp].push(state); + + if (completed.hasOwnProperty(exp)) { + var nulls = completed[exp]; + for (var i = 0; i < nulls.length; i++) { + var right = nulls[i]; + this.complete(state, right); + } + } + } else { + wants[exp] = [state]; + this.predict(exp); + } + } + } + }; + + Column.prototype.predict = function(exp) { + var rules = this.grammar.byName[exp] || []; + + for (var i = 0; i < rules.length; i++) { + var r = rules[i]; + var wantedBy = this.wants[exp]; + var s = new State(r, 0, this.index, wantedBy); + this.states.push(s); + } + }; + + Column.prototype.complete = function(left, right) { + var copy = left.nextState(right); + this.states.push(copy); + }; + + + function Grammar(rules, start) { + this.rules = rules; + this.start = start || this.rules[0].name; + var byName = this.byName = {}; + this.rules.forEach(function(rule) { + if (!byName.hasOwnProperty(rule.name)) { + byName[rule.name] = []; + } + byName[rule.name].push(rule); + }); + } + + // So we can allow passing (rules, start) directly to Parser for backwards compatibility + Grammar.fromCompiled = function(rules, start) { + var lexer = rules.Lexer; + if (rules.ParserStart) { + start = rules.ParserStart; + rules = rules.ParserRules; + } + var rules = rules.map(function (r) { return (new Rule(r.name, r.symbols, r.postprocess)); }); + var g = new Grammar(rules, start); + g.lexer = lexer; // nb. storing lexer on Grammar is iffy, but unavoidable + return g; + }; + + + function StreamLexer() { + this.reset(""); + } + + StreamLexer.prototype.reset = function(data, state) { + this.buffer = data; + this.index = 0; + this.line = state ? state.line : 1; + this.lastLineBreak = state ? -state.col : 0; + }; + + StreamLexer.prototype.next = function() { + if (this.index < this.buffer.length) { + var ch = this.buffer[this.index++]; + if (ch === '\n') { + this.line += 1; + this.lastLineBreak = this.index; + } + return {value: ch}; + } + }; + + StreamLexer.prototype.save = function() { + return { + line: this.line, + col: this.index - this.lastLineBreak, + } + }; + + StreamLexer.prototype.formatError = function(token, message) { + // nb. this gets called after consuming the offending token, + // so the culprit is index-1 + var buffer = this.buffer; + if (typeof buffer === 'string') { + var nextLineBreak = buffer.indexOf('\n', this.index); + if (nextLineBreak === -1) nextLineBreak = buffer.length; + var line = buffer.substring(this.lastLineBreak, nextLineBreak); + var col = this.index - this.lastLineBreak; + message += " at line " + this.line + " col " + col + ":\n\n"; + message += " " + line + "\n"; + message += " " + Array(col).join(" ") + "^"; + return message; + } else { + return message + " at index " + (this.index - 1); + } + }; + + + function Parser(rules, start, options) { + if (rules instanceof Grammar) { + var grammar = rules; + var options = start; + } else { + var grammar = Grammar.fromCompiled(rules, start); + } + this.grammar = grammar; + + // Read options + this.options = { + keepHistory: false, + lexer: grammar.lexer || new StreamLexer, + }; + for (var key in (options || {})) { + this.options[key] = options[key]; + } + + // Setup lexer + this.lexer = this.options.lexer; + this.lexerState = undefined; + + // Setup a table + var column = new Column(grammar, 0); + var table = this.table = [column]; + + // I could be expecting anything. + column.wants[grammar.start] = []; + column.predict(grammar.start); + // TODO what if start rule is nullable? + column.process(); + this.current = 0; // token index + } + + // create a reserved token for indicating a parse fail + Parser.fail = {}; + + Parser.prototype.feed = function(chunk) { + var lexer = this.lexer; + lexer.reset(chunk, this.lexerState); + + var token; + while (token = lexer.next()) { + // We add new states to table[current+1] + var column = this.table[this.current]; + + // GC unused states + if (!this.options.keepHistory) { + delete this.table[this.current - 1]; + } + + var n = this.current + 1; + var nextColumn = new Column(this.grammar, n); + this.table.push(nextColumn); + + // Advance all tokens that expect the symbol + var literal = token.value; + var value = lexer.constructor === StreamLexer ? token.value : token; + var scannable = column.scannable; + for (var w = scannable.length; w--; ) { + var state = scannable[w]; + var expect = state.rule.symbols[state.dot]; + // Try to consume the token + // either regex or literal + if (expect.test ? expect.test(value) : + expect.type ? expect.type === token.type + : expect.literal === literal) { + // Add it + var next = state.nextState({data: value, token: token, isToken: true, reference: n - 1}); + nextColumn.states.push(next); + } + } + + // Next, for each of the rules, we either + // (a) complete it, and try to see if the reference row expected that + // rule + // (b) predict the next nonterminal it expects by adding that + // nonterminal's start state + // To prevent duplication, we also keep track of rules we have already + // added + + nextColumn.process(); + + // If needed, throw an error: + if (nextColumn.states.length === 0) { + // No states at all! This is not good. + var message = this.lexer.formatError(token, "invalid syntax") + "\n"; + message += "Unexpected " + (token.type ? token.type + " token: " : ""); + message += JSON.stringify(token.value !== undefined ? token.value : token) + "\n"; + var err = new Error(message); + err.offset = this.current; + err.token = token; + throw err; + } + + // maybe save lexer state + if (this.options.keepHistory) { + column.lexerState = lexer.save(); + } + + this.current++; + } + if (column) { + this.lexerState = lexer.save(); + } + + // Incrementally keep track of results + this.results = this.finish(); + + // Allow chaining, for whatever it's worth + return this; + }; + + Parser.prototype.save = function() { + var column = this.table[this.current]; + column.lexerState = this.lexerState; + return column; + }; + + Parser.prototype.restore = function(column) { + var index = column.index; + this.current = index; + this.table[index] = column; + this.table.splice(index + 1); + this.lexerState = column.lexerState; + + // Incrementally keep track of results + this.results = this.finish(); + }; + + // nb. deprecated: use save/restore instead! + Parser.prototype.rewind = function(index) { + if (!this.options.keepHistory) { + throw new Error('set option `keepHistory` to enable rewinding') + } + // nb. recall column (table) indicies fall between token indicies. + // col 0 -- token 0 -- col 1 + this.restore(this.table[index]); + }; + + Parser.prototype.finish = function() { + // Return the possible parsings + var considerations = []; + var start = this.grammar.start; + var column = this.table[this.table.length - 1]; + column.states.forEach(function (t) { + if (t.rule.name === start + && t.dot === t.rule.symbols.length + && t.reference === 0 + && t.data !== Parser.fail) { + considerations.push(t); + } + }); + return considerations.map(function(c) {return c.data; }); + }; + + return { + Parser: Parser, + Grammar: Grammar, + Rule: Rule, + }; + +})(); + +var moo = (function() { + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + // polyfill assign(), so we support IE9+ + var assign = typeof Object.assign === 'function' ? Object.assign : + // https://tc39.github.io/ecma262/#sec-object.assign + function(target, sources) { + if (target == null) { + throw new TypeError('Target cannot be null or undefined'); + } + target = Object(target); + + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + if (source == null) continue + + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + return target + }; + + var hasSticky = typeof new RegExp().sticky === 'boolean'; + + /***************************************************************************/ + + function isRegExp(o) { return o && o.constructor === RegExp } + function isObject(o) { return o && typeof o === 'object' && o.constructor !== RegExp && !Array.isArray(o) } + + function reEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + } + function reGroups(s) { + var re = new RegExp('|' + s); + return re.exec('').length - 1 + } + function reCapture(s) { + return '(' + s + ')' + } + function reUnion(regexps) { + var source = regexps.map(function(s) { + return "(?:" + s + ")" + }).join('|'); + return "(?:" + source + ")" + } + + function regexpOrLiteral(obj) { + if (typeof obj === 'string') { + return '(?:' + reEscape(obj) + ')' + + } else if (isRegExp(obj)) { + // TODO: consider /u support + if (obj.ignoreCase) { throw new Error('RegExp /i flag not allowed') } + if (obj.global) { throw new Error('RegExp /g flag is implied') } + if (obj.sticky) { throw new Error('RegExp /y flag is implied') } + if (obj.multiline) { throw new Error('RegExp /m flag is implied') } + return obj.source + + } else { + throw new Error('not a pattern: ' + obj) + } + } + + function objectToRules(object) { + var keys = Object.getOwnPropertyNames(object); + var result = []; + for (var i=0; i 0) { + throw new Error("RegExp has capture groups: " + regexp + "\nUse (?: … ) instead") + } + if (!hasStates && (options.pop || options.push || options.next)) { + throw new Error("State-switching options are not allowed in stateless lexers (for token '" + options.tokenType + "')") + } + + // try and detect rules matching newlines + if (!options.lineBreaks && regexp.test('\n')) { + throw new Error('Rule should declare lineBreaks: ' + regexp) + } + + // store regex + parts.push(reCapture(pat)); + } + + var suffix = hasSticky ? '' : '|(?:)'; + var flags = hasSticky ? 'ym' : 'gm'; + var combined = new RegExp(reUnion(parts) + suffix, flags); + + return {regexp: combined, groups: groups, error: errorRule} + } + + function compile(rules) { + var result = compileRules(rules); + return new Lexer({start: result}, 'start') + } + + function compileStates(states, start) { + var keys = Object.getOwnPropertyNames(states); + if (!start) start = keys[0]; + + var map = Object.create(null); + for (var i=0; i', pop: true }, + beat_operators: ['|', '+', '-', '*', '/'] + } +}); + +let Nil = Symbol('Nil'); +let cast_bool = function (arg) { + if (arg === Nil || arg === false) { + return false; + } + else { + return true; + } +}; + +// does this have to be an Error? idc +class PlaybackError extends Error { + constructor(message, scope) { + super(`${message}\nScope: "${scope.name}"`); + } +} +/* Import-related errors */ +class ImportError extends PlaybackError { + constructor(message, scope) { + super(message, scope); + } +} +class NoSuchStyleError extends ImportError { + constructor(identifier, scope) { + super(`No style with the name "${identifier}" was imported`, scope); + } +} +class NoSuchTrackError extends ImportError { + constructor(style, track, scope) { + super(`No track with the name "${track}" exists in the style "${style}"`, scope); + } +} +class NoSuchPatternError extends ImportError { + constructor(style, track, pattern, scope) { + super(`Pattern "${style}.${track}.${pattern}" does not exist`, scope); + } +} +/* Function-related errors */ +class FunctionNameError extends PlaybackError { + constructor(identifier, scope) { + super(`No function exists with name "${identifier}"`, scope); + } +} +class FunctionScopeError extends PlaybackError { + constructor(message, scope) { + super(message, scope); + } +} +class FunctionArgumentsError extends PlaybackError { + constructor(message, scope) { + super(message, scope); + } +} +/* Pattern-related errors */ +class TooManyBeatsError extends PlaybackError { + constructor(scope) { + super('Pattern may only contain 1 BeatGroup. Try the join operator "&"', scope); + } +} +/* Beat-related errors*/ +class MelodicBeatInDrumBeatGroupError extends PlaybackError { + constructor(scope) { + super('Unexpected Melodic Beat in a Drum Beat Group', scope); + } +} +class DrumBeatInMelodicBeatGroupError extends PlaybackError { + constructor(scope) { + super('Unexpected Drum Beat in a Melodic Beat Group', scope); + } +} + +/* + * In Playback styles, basically any pair of curly brackets defines a scope + * which inherits settings from its parent scope but can overwrite them. + */ +class Scope { + constructor() { + this.defaultVars = new Map(); + this.vars = new Map(); + this.name = null; + this.type = null; + this.scope = null; + } + inherit() { + this.vars = new Map([...this.defaultVars, ...this.scope.vars]); + } + init(scope) { + this.scope = scope; + // in case this.vars was set in the constructor + this.vars = new Map([...this.defaultVars, ...this.scope.vars, ...this.vars]); + } +} + +class MetaStatement extends Scope { + constructor(functionCalls) { + super(); + this.name = '@meta'; + this.type = '@meta'; + this.functionCalls = functionCalls; + } + init(scope) { + this.scope = scope; + // nothing in here can be dynamic so resolve these at compile time + for (let functionCall of this.functionCalls) { + functionCall.init(this); + functionCall.execute(); + } + scope.metadata = this.vars; + } +} +class OptionsStatement extends Scope { + constructor(functionCalls) { + super(); + this.name = '@options'; + this.type = '@options'; + this.functionCalls = functionCalls; + } + init(scope) { + // nothing in here /should/ be dynamic so resolve these at compile time + for (let functionCall of this.functionCalls) { + functionCall.init(this); + functionCall.execute(); + } + this.scope = scope; + // in this case we're actually overwriting our scope's variables, not + // vise-versa + scope.vars = new Map([...scope.vars, ...this.vars]); + } +} +class ImportStatement { + constructor(path, identifier) { + this.path = path; + this.identifier = identifier; + } +} + +var drumJson = { + "26": "Silence", + "27": "High-Q", + "28": "Slap", + "29": "Scratch Push", + "30": "Scratch Pull", + "31": "Sticks", + "32": "Square Click", + "33": "Metronome Click", + "34": "Metronome Bell", + "35": "Acoustic Bass Drum", + "36": "Bass Drum", + "37": "Side Stick", + "38": "Acoustic Snare", + "39": "Hand Clap", + "40": "Electric Snare", + "41": "Low Floor Tom", + "42": "Closed Hi Hat", + "43": "High Floor Tom", + "44": "Pedal Hi-Hat", + "45": "Low Tom", + "46": "Open Hi-Hat", + "47": "Low-Mid Tom", + "48": "Hi-Mid Tom", + "49": "Crash Cymbal 1", + "50": "High Tom", + "51": "Ride Cymbal 1", + "52": "Chinese Cymbal", + "53": "Ride Bell", + "54": "Tambourine", + "55": "Splash Cymbal", + "56": "Cowbell", + "57": "Crash Cymbal 2", + "58": "Vibraslap", + "59": "Ride Cymbal 2", + "60": "Hi Bongo", + "61": "Low Bongo", + "62": "Mute Hi Conga", + "63": "Open Hi Conga", + "64": "Low Conga", + "65": "High Timbale", + "66": "Low Timbale", + "67": "High Agogo", + "68": "Low Agogo", + "69": "Cabasa", + "70": "Maracas", + "71": "Short Whistle", + "72": "Long Whistle", + "73": "Short Guiro", + "74": "Long Guiro", + "75": "Claves", + "76": "Hi Wood Block", + "77": "Low Wood Block", + "78": "Mute Cuica", + "79": "Open Cuica", + "80": "Mute Triangle", + "81": "Open Triangle", + "82": "Shaker", + "83": "Jingle Bell", + "84": "Bell Tree", + "85": "Castanets", + "86": "Mute Surdo", + "87": "Open Surdo" +}; + +const tonal = _Tonal__default || _Tonal; +/** + * There are some inconsistencies with the official MIDI drum names, this + * transformation will hopefully ease the pain there. + * Note: What's the more general word for case-folding? Just "normalizing"? Eh + * @param {string} name + * @return {string} + */ +function normalizeDrumName(name) { + return name.toLowerCase().replace(/ |-|_/g, ' '); +} +// make a map of drum names, which is the inverse of the given JSON file +let DRUM_MAP = new Map(); +for (let midi in drumJson) { + let name = normalizeDrumName(drumJson[midi]); + DRUM_MAP.set(name, midi); +} +/** + * Special pitch value meaning the note will be set later by a DrumBeatGroup + */ +let AwaitingDrum = Symbol('AwaitingDrum'); +class Note { + /** + * @param {Object} opts Options object. + * @param {number} opts.time The note's time, in beats. + * @param {string | symbol} opts.pitch A string representing the pitch and octave of the note. e.x. 'A4' + * @param {number} opts.duraion The note's duration, in beats. + * @param {number} opts.volume The note's volume, as a float 0-1 (inclusive). + */ + constructor(opts) { + this.time = opts.time; + this.pitch = opts.pitch; + this.duration = opts.duration; + this.volume = opts.volume; + } + /** + * An integer representing the MIDI pitch value of the note. + * @type {number} + */ + get midi() { + if (this.pitch === AwaitingDrum) { + return null; + } + else { + let drumValue = DRUM_MAP.get(normalizeDrumName(this.pitch)); + if (drumValue) { + return drumValue; + } + else { + return tonal.Note.midi(this.pitch); + } + } + } + /** + * An integer 0-127 that roughly correlates to volume + * @type {number} + */ + get velocity() { + return Math.floor(this.volume * 127); + } +} +class NoteSet extends Array { + constructor(...args) { + super(); + this.push(...args); + } +} + +let tonal$1 = {}; +(function(n){function t(n){"string"!=typeof n&&(n="");var t=T.exec(n);return t?[t[1].toUpperCase(),t[2].replace(/x/g,"##"),t[3],t[4]]:null}function r(n,t){return n=Math.round(n),(!0===t?G:I)[n%12]+(Math.floor(n/12)-1)}function e(n,t){for(var r=[];t--;r[t]=t+n);return r}function m(n,t){for(var r=[];t--;r[t]=n-t);return r}function i(n,t){return null===n||null===t?[]:nan(t)})}function P(n){return o(n).filter(function(n,t,r){return 0===t||n!==r[t-1]})}function M(n){return "string"!=typeof n?An:_n[n]||(_n[n]=xn(n))}function a(n){var t=(n+1)%7;return t<0?7+t:t}function l(n,t){if(1===arguments.length)return function(t){return l(n,t)};var r=Kn(n),e=Qn(t);if(null===r||null===e)return null;var m=1===r.length?[r[0]+e[0]]:[r[0]+e[0],r[1]+e[1]];return mn(Un(m[0],m[1]))}function c(n,t){if(1===arguments.length)return function(t){return c(n,t)};var r=Kn(n);return null===r?null:mn(Un(r[0]+t))}function s(n,t){if(1===arguments.length)return function(t){return s(n,t)};var r=Kn(n),e=Kn(t);return null===e||null===r?null:e[0]-r[0]}function f(n,t){return 1===arguments.length?function(t){return l(t,n)}:l(t,n)}function d(n,t,r){var e=Qn(n),m=Qn(t);if(null===e||null===m)return null;var i=[e[0]+r*m[0],e[1]+r*m[1]];return Dn(Wn(i))}function p(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,1)}function b(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,-1)}function h(n,t){if(1===arguments.length)return function(t){return h(n,t)};var r=Kn(n),e=Kn(t);if(null===r||null===e||r.length!==e.length)return null;var m=1===r.length?[e[0]-r[0],-Math.floor(7*(e[0]-r[0])/12)]:[e[0]-r[0],e[1]-r[1]];return Dn(Wn(m))}function v(n,t){if(1===arguments.length)return function(t){return v(n,t)};var r=L(n),e=L(t);return null!==r.midi&&null!==e.midi?e.midi-r.midi:null!==r.chroma&&null!==e.chroma?(e.chroma-r.chroma+12)%12:null}function A(n){if(y(n))return n;if(!Array.isArray(n))return "";var t=[0,0,0,0,0,0,0,0,0,0,0,0];return n.map(nt).forEach(function(n){t[n]=1;}),t.join("")}function g(n){return et=et||i(2048,4095).map(function(n){return n.toString(2)}),"number"==typeof n?et.filter(function(t){return rt(t)===n}):et.slice()}function j(n,t){t=!1!==t;var r=A(n).split("");return Mn(r.map(function(n,e){var m=u(e,r);return t&&"0"===m[0]?null:m.join("")}))}function y(n){return mt.test(n)}function O(n){return y(n)?Mn(n.split("").map(function(n,t){return "1"===n?it[t]:null})):[]}function x(n,t){return 1===arguments.length?function(t){return x(n,t)}:A(n)===A(t)}function _(n,t){return arguments.length>1?_(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t&n)===t})}function z(n,t){return arguments.length>1?z(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t|n)===t})}function q(n,t){return arguments.length>1?q(n)(t):(n=A(n),function(t){return "1"===n[nt(t)]})}function k(n,t){return 1===arguments.length?function(t){return k(n,t)}:t.filter(q(n))}function S(n,t){var r=D(n);return t=t||r[1],pt(t).map(l(r[0]))}function w(n){var t=D(n);return void 0!==Mt(t[1])}function D(n){if("string"!=typeof n)return ["",""];var t=n.indexOf(" "),r=R(n.substring(0,t))||R(n)||"",e=""!==r?n.substring(r.length+1):n;return [r,e.length?e:""]}function E(n,t){var r=C(n);return t=t||r[1],xt(t).intervals.map(l(r[0]))}function C(n){var r=t(n);return ""===r[0]?["",n]:"A"===r[0]&&"ug"===r[3]?["","aug"]:St.test(r[2])?[r[0]+r[1],r[2]+r[3]]:[r[0]+r[1]+r[2],r[3]]}var $="C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B".split(" "),F=function(n){return "string"!=typeof n?$.slice():$.filter(function(t){var r=t[1]||" ";return -1!==n.indexOf(r)})},G=F(" #"),I=F(" b"),T=/^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)$/,B=Object.freeze({pc:null,name:null,step:null,alt:null,oct:null,octStr:null,chroma:null,midi:null,freq:null}),N=[0,2,4,5,7,9,11],L=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var r=t(n);if(""===r[0]||""!==r[3])return B;var e=r[0],m=r[1],i=r[2],u={letter:e,acc:m,octStr:i};return u.pc=u.letter+u.acc,u.name=u.pc+i,u.step=(u.letter.charCodeAt(0)+3)%7,u.alt="b"===u.acc[0]?-u.acc.length:u.acc.length,u.oct=i.length?+i:null,u.chroma=(N[u.step]+u.alt+120)%12,u.midi=null!==u.oct?N[u.step]+u.alt+12*(u.oct+1):null,u.freq=J(u.midi),Object.freeze(u)}),R=function(n){return L(n).name},U=function(n){return L(n).pc},H=function(n){return L(n).midi||+n||null},J=function(n,t){return void 0===t&&(t=440),"number"==typeof n?Math.pow(2,(n-69)/12)*t:null},K=function(n){return L(n).freq||J(n)},Q=Math.log(2),V=Math.log(440),W=function(n){var t=12*(Math.log(n)-V)/Q+69;return Math.round(100*t)/100},X=function(n){return L(n).chroma},Y=function(n){return L(n).oct},Z=function(n){return "CDEFGAB"[n]},nn=function(n,t){return Array(t+1).join(n)},tn=function(n,t){return "number"!=typeof n?"":t(n)},rn=function(n){return tn(n,function(n){return n<0?nn("b",-n):nn("#",n)})},en=function(n,t){void 0===n&&(n={}),void 0===t&&(t=null);var r=t?Object.assign({},L(t),n):n,e=r.step,m=r.alt,i=r.oct,u=Z(e);if(!u)return null;var o=u+rn(m);return i||0===i?o+i:o},mn=en,un=function(n,t){var e=L(n),m=e.alt,i=e.chroma,u=e.midi;if(null===i)return null;var o=!1===t?m<0:m>0;return null===u?U(r(i,o)):r(u,o)},on=function(n){return un(n,!1)},Pn=Object.freeze({names:F,tokenize:t,props:L,name:R,pc:U,midi:H,midiToFreq:J,freq:K,freqToMidi:W,chroma:X,oct:Y,stepToLetter:Z,altToAcc:rn,from:en,build:mn,fromMidi:r,simplify:un,enharmonic:on}),Mn=function(n){return n.filter(function(n){return 0===n||n})},an=function(n){var t=H(n);return null!==t?t:H(n+"-100")},ln=function(n,t){void 0===t&&(t=Math.random);for(var r,e,m=n.length;m;)r=t()*m--|0,e=n[m],n[m]=n[r],n[r]=e;return n},cn=function(n){return 0===n.length?[[]]:cn(n.slice(1)).reduce(function(t,r){return t.concat(n.map(function(t,e){var m=r.slice();return m.splice(e,0,n[0]),m}))},[])},sn=Object.freeze({range:i,rotate:u,compact:Mn,sort:o,unique:P,shuffle:ln,permutations:cn}),fn=new RegExp("^([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})|(AA|A|P|M|m|d|dd)([-+]?\\d+)$"),dn=[0,2,4,5,7,9,11],pn=[0,1,2,3,4,5,6,5,4,3,2,1],bn="1P 2m 2M 3m 3M 4P 5P 6m 6M 7m 7M 8P".split(" "),hn=function(n){return "string"!=typeof n?bn.slice():bn.filter(function(t){return -1!==n.indexOf(t[1])})},vn=function(n){var t=fn.exec(n);return null===t?null:t[1]?[t[1],t[2]]:[t[4],t[3]]},An=Object.freeze({name:null,num:null,q:null,step:null,alt:null,dir:null,type:null,simple:null,semitones:null,chroma:null}),gn=function(n,t){return Array(Math.abs(t)+1).join(n)},jn=function(n,t){return "M"===t&&"M"===n?0:"P"===t&&"P"===n?0:"m"===t&&"M"===n?-1:/^A+$/.test(t)?t.length:/^d+$/.test(t)?"P"===n?-t.length:-t.length-1:null},yn=function(n,t){return 0===t?"M"===n?"M":"P":-1===t&&"M"===n?"m":t>0?gn("A",t):t<0?gn("d","P"===n?t:t+1):null},On=function(n){return (Math.abs(n)-1)%7},xn=function(n){var t=vn(n);if(null===t)return An;var r={num:+t[0],q:t[1]};return r.step=On(r.num),r.type="PMMPPMM"[r.step],"M"===r.type&&"P"===r.q?An:(r.name=""+r.num+r.q,r.dir=r.num<0?-1:1,r.simple=8===r.num||-8===r.num?r.num:r.dir*(r.step+1),r.alt=jn(r.type,r.q),r.oct=Math.floor((Math.abs(r.num)-1)/7),r.semitones=r.dir*(dn[r.step]+r.alt+12*r.oct),r.chroma=(r.dir*(dn[r.step]+r.alt)%12+12)%12,Object.freeze(r))},_n={},zn=function(n){return M(n).num},qn=function(n){return M(n).name},kn=function(n){return M(n).semitones},Sn=function(n){return M(n).chroma},wn=function(n){return "string"==typeof n&&(n=M(n).chroma),"number"==typeof n?pn[n%12]:null},Dn=function(n){void 0===n&&(n={});var t=n.num,r=n.step,e=n.alt,m=n.oct;void 0===m&&(m=1);var i=n.dir;if(void 0!==r&&(t=r+1+7*m),void 0===t)return null;var u=i<0?"-":"",o="PMMPPMM"[On(t)];return u+t+yn(o,e)},En=function(n){var t=M(n);return t===An?null:t.simple+t.q},Cn=function(n){var t=M(n);if(t===An)return null;var r=(7-t.step)%7,e="P"===t.type?-t.alt:-(t.alt+1);return Dn({step:r,alt:e,oct:t.oct,dir:t.dir})},$n=[1,2,2,3,3,4,5,5,6,6,7,7],Fn="P m M m M P d P m M m M".split(" "),Gn=function(n){var t=n<0?-1:1,r=Math.abs(n),e=r%12,m=Math.floor(r/12);return t*($n[e]+7*m)+Fn[e]},In=Object.freeze({names:hn,tokenize:vn,props:M,num:zn,name:qn,semitones:kn,chroma:Sn,ic:wn,build:Dn,simplify:En,invert:Cn,fromSemitones:Gn}),Tn=[0,2,4,-1,1,3,5],Bn=function(n){return Math.floor(7*n/12)},Nn=Tn.map(Bn),Ln=function(n){var t=n.step,r=n.alt,e=n.oct,m=n.dir;void 0===m&&(m=1);var i=Tn[t]+7*r;return null===e?[m*i]:[m*i,m*(e-Nn[t]-4*r)]},Rn=[3,0,4,1,5,2,6],Un=function(n,t,r){var e=Rn[a(n)],m=Math.floor((n+1)/7);return void 0===t?{step:e,alt:m,dir:r}:{step:e,alt:m,oct:t+4*m+Nn[e],dir:r}},Hn=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}},Jn=function(n){return Hn(function(t){var r=n(t);return null===r.name?null:Ln(r)})},Kn=Jn(L),Qn=Jn(M),Vn=function(n){return 7*n[0]+12*n[1]<0},Wn=function(n){return Vn(n)?Un(-n[0],-n[1],-1):Un(n[0],n[1],1)},Xn=Object.freeze({transpose:l,trFifths:c,fifths:s,transposeBy:f,addIntervals:d,add:p,subtract:b,interval:h,semitones:v}),Yn={chromatic:["1P 2m 2M 3m 3M 4P 4A 5P 6m 6M 7m 7M"],lydian:["1P 2M 3M 4A 5P 6M 7M"],major:["1P 2M 3M 4P 5P 6M 7M",["ionian"]],mixolydian:["1P 2M 3M 4P 5P 6M 7m",["dominant"]],dorian:["1P 2M 3m 4P 5P 6M 7m"],aeolian:["1P 2M 3m 4P 5P 6m 7m",["minor"]],phrygian:["1P 2m 3m 4P 5P 6m 7m"],locrian:["1P 2m 3m 4P 5d 6m 7m"],altered:["1P 2m 3m 3M 5d 6m 7m",["super locrian","diminished whole tone","pomeroy"]],iwato:["1P 2m 4P 5d 7m"],hirajoshi:["1P 2M 3m 5P 6m"],kumoijoshi:["1P 2m 4P 5P 6m"],pelog:["1P 2m 3m 5P 6m"],prometheus:["1P 2M 3M 4A 6M 7m"],ritusen:["1P 2M 4P 5P 6M"],scriabin:["1P 2m 3M 5P 6M"],piongio:["1P 2M 4P 5P 6M 7m"],augmented:["1P 2A 3M 5P 5A 7M"],neopolitan:["1P 2m 3m 4P 5P 6m 7M"],diminished:["1P 2M 3m 4P 5d 6m 6M 7M"],egyptian:["1P 2M 4P 5P 7m"],oriental:["1P 2m 3M 4P 5d 6M 7m"],spanish:["1P 2m 3M 4P 5P 6m 7m",["phrygian major"]],flamenco:["1P 2m 3m 3M 4A 5P 7m"],balinese:["1P 2m 3m 4P 5P 6m 7M"],persian:["1P 2m 3M 4P 5d 6m 7M"],bebop:["1P 2M 3M 4P 5P 6M 7m 7M"],enigmatic:["1P 2m 3M 5d 6m 7m 7M"],ichikosucho:["1P 2M 3M 4P 5d 5P 6M 7M"],"melodic minor":["1P 2M 3m 4P 5P 6M 7M"],"melodic minor second mode":["1P 2m 3m 4P 5P 6M 7m"],"lydian augmented":["1P 2M 3M 4A 5A 6M 7M"],"lydian dominant":["1P 2M 3M 4A 5P 6M 7m",["lydian b7"]],"melodic minor fifth mode":["1P 2M 3M 4P 5P 6m 7m",["hindu","mixolydian b6M"]],"locrian #2":["1P 2M 3m 4P 5d 6m 7m"],"locrian major":["1P 2M 3M 4P 5d 6m 7m",["arabian"]],"major pentatonic":["1P 2M 3M 5P 6M",["pentatonic"]],"lydian pentatonic":["1P 3M 4A 5P 7M",["chinese"]],"mixolydian pentatonic":["1P 3M 4P 5P 7m",["indian"]],"locrian pentatonic":["1P 3m 4P 5d 7m",["minor seven flat five pentatonic"]],"minor pentatonic":["1P 3m 4P 5P 7m"],"minor six pentatonic":["1P 3m 4P 5P 6M"],"minor hexatonic":["1P 2M 3m 4P 5P 7M"],"flat three pentatonic":["1P 2M 3m 5P 6M",["kumoi"]],"flat six pentatonic":["1P 2M 3M 5P 6m"],"major flat two pentatonic":["1P 2m 3M 5P 6M"],"whole tone pentatonic":["1P 3M 5d 6m 7m"],"ionian pentatonic":["1P 3M 4P 5P 7M"],"lydian #5P pentatonic":["1P 3M 4A 5A 7M"],"lydian dominant pentatonic":["1P 3M 4A 5P 7m"],"minor #7M pentatonic":["1P 3m 4P 5P 7M"],"super locrian pentatonic":["1P 3m 4d 5d 7m"],"in-sen":["1P 2m 4P 5P 7m"],"vietnamese 1":["1P 3m 4P 5P 6m"],"vietnamese 2":["1P 3m 4P 5P 7m"],"prometheus neopolitan":["1P 2m 3M 4A 6M 7m"],"major blues":["1P 2M 3m 3M 5P 6M"],"minor blues":["1P 3m 4P 5d 5P 7m",["blues"]],"composite blues":["1P 2M 3m 3M 4P 5d 5P 6M 7m"],"augmented heptatonic":["1P 2A 3M 4P 5P 5A 7M"],"dorian #4":["1P 2M 3m 4A 5P 6M 7m"],"lydian diminished":["1P 2M 3m 4A 5P 6M 7M"],"whole tone":["1P 2M 3M 4A 5A 7m"],"leading whole tone":["1P 2M 3M 4A 5A 7m 7M"],"harmonic minor":["1P 2M 3m 4P 5P 6m 7M"],"lydian minor":["1P 2M 3M 4A 5P 6m 7m"],"neopolitan minor":["1P 2m 3m 4P 5P 6m 7M"],"neopolitan major":["1P 2m 3m 4P 5P 6M 7M",["dorian b2"]],"neopolitan major pentatonic":["1P 3M 4P 5d 7m"],"romanian minor":["1P 2M 3m 5d 5P 6M 7m"],"double harmonic lydian":["1P 2m 3M 4A 5P 6m 7M"],"harmonic major":["1P 2M 3M 4P 5P 6m 7M"],"double harmonic major":["1P 2m 3M 4P 5P 6m 7M",["gypsy"]],"hungarian minor":["1P 2M 3m 4A 5P 6m 7M"],"hungarian major":["1P 2A 3M 4A 5P 6M 7m"],"spanish heptatonic":["1P 2m 3m 3M 4P 5P 6m 7m"],"todi raga":["1P 2m 3m 4A 5P 6m 7M"],"malkos raga":["1P 3m 4P 6m 7m"],"kafi raga":["1P 3m 3M 4P 5P 6M 7m 7M"],"purvi raga":["1P 2m 3M 4P 4A 5P 6m 7M"],"bebop dominant":["1P 2M 3M 4P 5P 6M 7m 7M"],"bebop minor":["1P 2M 3m 3M 4P 5P 6M 7m"],"bebop major":["1P 2M 3M 4P 5P 5A 6M 7M"],"bebop locrian":["1P 2m 3m 4P 5d 5P 6m 7m"],"minor bebop":["1P 2M 3m 4P 5P 6m 7m 7M"],"mystery #1":["1P 2m 3M 5d 6m 7m"],"minor six diminished":["1P 2M 3m 4P 5P 6m 6M 7M"],"ionian augmented":["1P 2M 3M 4P 5A 6M 7M"],"lydian #9":["1P 2m 3M 4A 5P 6M 7M"],"six tone symmetric":["1P 2m 3M 4P 5A 6M"]},Zn={M:["1P 3M 5P",["Major",""]],M13:["1P 3M 5P 7M 9M 13M",["maj13","Maj13"]],M6:["1P 3M 5P 13M",["6"]],M69:["1P 3M 5P 6M 9M",["69"]],M7add13:["1P 3M 5P 6M 7M 9M"],M7b5:["1P 3M 5d 7M"],M7b6:["1P 3M 6m 7M"],M7b9:["1P 3M 5P 7M 9m"],M7sus4:["1P 4P 5P 7M"],M9:["1P 3M 5P 7M 9M",["maj9","Maj9"]],M9b5:["1P 3M 5d 7M 9M"],M9sus4:["1P 4P 5P 7M 9M"],Madd9:["1P 3M 5P 9M",["2","add9","add2"]],Maj7:["1P 3M 5P 7M",["maj7","M7"]],Mb5:["1P 3M 5d"],Mb6:["1P 3M 13m"],Msus2:["1P 2M 5P",["add9no3","sus2"]],Msus4:["1P 4P 5P",["sus","sus4"]],Maddb9:["1P 3M 5P 9m"],m:["1P 3m 5P"],m11:["1P 3m 5P 7m 9M 11P",["_11"]],m11b5:["1P 3m 7m 12d 2M 4P",["h11","_11b5"]],m13:["1P 3m 5P 7m 9M 11P 13M",["_13"]],m6:["1P 3m 4P 5P 13M",["_6"]],m69:["1P 3m 5P 6M 9M",["_69"]],m7:["1P 3m 5P 7m",["minor7","_","_7"]],m7add11:["1P 3m 5P 7m 11P",["m7add4"]],m7b5:["1P 3m 5d 7m",["half-diminished","h7","_7b5"]],m9:["1P 3m 5P 7m 9M",["_9"]],m9b5:["1P 3m 7m 12d 2M",["h9","-9b5"]],mMaj7:["1P 3m 5P 7M",["mM7","_M7"]],mMaj7b6:["1P 3m 5P 6m 7M",["mM7b6"]],mM9:["1P 3m 5P 7M 9M",["mMaj9","-M9"]],mM9b6:["1P 3m 5P 6m 7M 9M",["mMaj9b6"]],mb6M7:["1P 3m 6m 7M"],mb6b9:["1P 3m 6m 9m"],o:["1P 3m 5d",["mb5","dim"]],o7:["1P 3m 5d 13M",["diminished","m6b5","dim7"]],o7M7:["1P 3m 5d 6M 7M"],oM7:["1P 3m 5d 7M"],sus24:["1P 2M 4P 5P",["sus4add9"]],madd4:["1P 3m 4P 5P"],madd9:["1P 3m 5P 9M"],4:["1P 4P 7m 10m",["quartal"]],5:["1P 5P"],7:["1P 3M 5P 7m",["Dominant","Dom"]],9:["1P 3M 5P 7m 9M",["79"]],11:["1P 5P 7m 9M 11P"],13:["1P 3M 5P 7m 9M 13M",["13_"]],64:["5P 8P 10M"],"M#5":["1P 3M 5A",["augmented","maj#5","Maj#5","+","aug"]],"M#5add9":["1P 3M 5A 9M",["+add9"]],"M13#11":["1P 3M 5P 7M 9M 11A 13M",["maj13#11","Maj13#11","M13+4","M13#4"]],"M6#11":["1P 3M 5P 6M 11A",["M6b5","6#11","6b5"]],"M69#11":["1P 3M 5P 6M 9M 11A"],"M7#11":["1P 3M 5P 7M 11A",["maj7#11","Maj7#11","M7+4","M7#4"]],"M7#5":["1P 3M 5A 7M",["maj7#5","Maj7#5","maj9#5","M7+"]],"M7#5sus4":["1P 4P 5A 7M"],"M7#9#11":["1P 3M 5P 7M 9A 11A"],"M9#11":["1P 3M 5P 7M 9M 11A",["maj9#11","Maj9#11","M9+4","M9#4"]],"M9#5":["1P 3M 5A 7M 9M",["Maj9#5"]],"M9#5sus4":["1P 4P 5A 7M 9M"],"11b9":["1P 5P 7m 9m 11P"],"13#11":["1P 3M 5P 7m 9M 11A 13M",["13+4","13#4"]],"13#9":["1P 3M 5P 7m 9A 13M",["13#9_"]],"13#9#11":["1P 3M 5P 7m 9A 11A 13M"],"13b5":["1P 3M 5d 6M 7m 9M"],"13b9":["1P 3M 5P 7m 9m 13M"],"13b9#11":["1P 3M 5P 7m 9m 11A 13M"],"13no5":["1P 3M 7m 9M 13M"],"13sus4":["1P 4P 5P 7m 9M 13M",["13sus"]],"69#11":["1P 3M 5P 6M 9M 11A"],"7#11":["1P 3M 5P 7m 11A",["7+4","7#4","7#11_","7#4_"]],"7#11b13":["1P 3M 5P 7m 11A 13m",["7b5b13"]],"7#5":["1P 3M 5A 7m",["+7","7aug","aug7"]],"7#5#9":["1P 3M 5A 7m 9A",["7alt","7#5#9_","7#9b13_"]],"7#5b9":["1P 3M 5A 7m 9m"],"7#5b9#11":["1P 3M 5A 7m 9m 11A"],"7#5sus4":["1P 4P 5A 7m"],"7#9":["1P 3M 5P 7m 9A",["7#9_"]],"7#9#11":["1P 3M 5P 7m 9A 11A",["7b5#9"]],"7#9#11b13":["1P 3M 5P 7m 9A 11A 13m"],"7#9b13":["1P 3M 5P 7m 9A 13m"],"7add6":["1P 3M 5P 7m 13M",["67","7add13"]],"7b13":["1P 3M 7m 13m"],"7b5":["1P 3M 5d 7m"],"7b6":["1P 3M 5P 6m 7m"],"7b9":["1P 3M 5P 7m 9m"],"7b9#11":["1P 3M 5P 7m 9m 11A",["7b5b9"]],"7b9#9":["1P 3M 5P 7m 9m 9A"],"7b9b13":["1P 3M 5P 7m 9m 13m"],"7b9b13#11":["1P 3M 5P 7m 9m 11A 13m",["7b9#11b13","7b5b9b13"]],"7no5":["1P 3M 7m"],"7sus4":["1P 4P 5P 7m",["7sus"]],"7sus4b9":["1P 4P 5P 7m 9m",["susb9","7susb9","7b9sus","7b9sus4","phryg"]],"7sus4b9b13":["1P 4P 5P 7m 9m 13m",["7b9b13sus4"]],"9#11":["1P 3M 5P 7m 9M 11A",["9+4","9#4","9#11_","9#4_"]],"9#11b13":["1P 3M 5P 7m 9M 11A 13m",["9b5b13"]],"9#5":["1P 3M 5A 7m 9M",["9+"]],"9#5#11":["1P 3M 5A 7m 9M 11A"],"9b13":["1P 3M 7m 9M 13m"],"9b5":["1P 3M 5d 7m 9M"],"9no5":["1P 3M 7m 9M"],"9sus4":["1P 4P 5P 7m 9M",["9sus"]],"m#5":["1P 3m 5A",["m+","mb6"]],"m11A 5":["1P 3m 6m 7m 9M 11P"],"m7#5":["1P 3m 6m 7m"],"m9#5":["1P 3m 6m 7m 9M"],"+add#9":["1P 3M 5A 9A"]},nt=function(n){return X(n)||Sn(n)||0},tt=function(n){return parseInt(A(n),2)},rt=function(n){return n.replace(/0/g,"").length},et=null,mt=/^[01]{12}$/,it="1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M".split(" "),ut=Object.freeze({chroma:A,chromas:g,modes:j,isChroma:y,intervals:O,isEqual:x,isSubsetOf:_,isSupersetOf:z,includes:q,filter:k}),ot=function(n){var t=Object.keys(n).sort(),r=[],e=[],m=function(n,t,m){r[n]=t,e[m]=e[m]||[],e[m].push(n);};t.forEach(function(t){var r=n[t][0].split(" "),e=n[t][1],i=A(r);m(t,r,i),e&&e.forEach(function(n){return m(n,r,i)});});var i=Object.keys(r).sort(),u=function(n){return r[n]};return u.names=function(n){return "string"==typeof n?(e[n]||[]).slice():(!0===n?i:t).slice()},u},Pt=function(n,t){var r=function(r){return n(r)||t(r)};return r.names=function(r){return n.names(r).concat(t.names(r))},r},Mt=ot(Yn),at=ot(Zn),lt=Pt(Mt,at),ct=Object.freeze({dictionary:ot,combine:Pt,scale:Mt,chord:at,pcset:lt}),st=Object.freeze({name:null,intervals:[],names:[],chroma:null,setnum:null}),ft=function(n,t){return function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=Mt(n);if(!t)return st;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=Mt.names(r.chroma),Object.freeze(r)},{}),dt=Mt.names,pt=function(n){var t=D(n);return ft(t[1]).intervals},bt=function(n){var t=pt(n),r=S(n);return j(t).map(function(n,e){var m=Mt.names(n)[0];if(m)return [r[e]||t[e],m]}).filter(function(n){return n})},ht=function(n){var t=_(pt(n));return at.names().filter(function(n){return t(at(n))})},vt=function(n){var t=Mn(n.map(U));if(!t.length)return t;var r=t[0],e=P(t);return u(e.indexOf(r),e)},At=function(n){if(!pt(n).length)return [];var t=z(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},gt=function(n){var t=_(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},jt=Object.freeze({props:ft,names:dt,intervals:pt,notes:S,exists:w,tokenize:D,modeNames:bt,chords:ht,toScale:vt,supersets:At,subsets:gt}),yt=at.names,Ot=Object.freeze({name:null,names:[],intervals:[],chroma:null,setnum:null}),xt=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=at(n);if(!t)return Ot;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=at.names(r.chroma),r}),_t=function(n){return xt(C(n)[1]).intervals},zt=function(n){return void 0!==at(C(n)[1])},qt=function(n){if(!_t(n).length)return [];var t=z(_t(n));return at.names().filter(function(n){return t(at(n))})},kt=function(n){var t=_(_t(n));return at.names().filter(function(n){return t(at(n))})},St=/^(6|64|7|9|11|13)$/,wt=Object.freeze({names:yt,props:xt,intervals:_t,notes:E,exists:zt,supersets:qt,subsets:kt,tokenize:C}),Dt=l,Et=h,Ct=L,$t=H,Ft=K,Gt=at,It=Mt;n.Array=sn,n.Note=Pn,n.Interval=In,n.Distance=Xn,n.Scale=jt,n.Chord=wt,n.PcSet=ut,n.Dictionary=ct,n.transpose=Dt,n.interval=Et,n.note=Ct,n.midi=$t,n.freq=Ft,n.chord=Gt,n.scale=It,Object.defineProperty(n,"__esModule",{value:!0});})(tonal$1); + +//import {Nil} from './type_utils.js'; +class MelodicBeatLiteral { + constructor(opts) { + this.time = opts.time || { time: 'auto' }; + this.pitch = opts.pitch; + this.octave = opts.octave || 'inherit'; + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + if (this.time.time === 'auto') { + return this.indexInMeasure + 1; + } + else { + return this.time.time; + } + } + /** + * Normalize a chord into a form tonal can handle + * @param {string} [chord=''] + * @return {string} + */ + static normalizeChord(chord = '') { + return chord + .replace(/-/g, '_') // tonal uses _ over - for minor7 + .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? + } + static chordToScaleName(chord) { + let chordType = tonal$1.Chord.tokenize(chord)[1]; + // @TODO: make this more robust + let names = tonal$1.Chord.props(chordType).names; + if (names.includes('dim')) + return 'diminished'; + if (names.includes('aug')) + return 'augmented'; + if (names.includes('Major')) + return 'major'; + if (names.includes('minor')) + return 'minor'; + if (names.includes('minor7')) + return 'dorian'; + if (names.includes('Dominant')) + return 'mixolydian'; + // if none of the above match, do our best to find the closest fit + let closestScale = 'major'; + names.forEach(name => { + if (name.startsWith('dim')) + closestScale = 'diminished'; + if (name.startsWith('aug')) + closestScale = 'augmented'; + if (name.startsWith('M')) + closestScale = 'major'; + if (name.startsWith('m')) + closestScale = 'minor'; + }); + return closestScale; + } + handleInversion(songIterator, pitches) { + let tonicPC = songIterator.song.getTransposedKey(); + let tonicNote = tonal$1.Note.from({ oct: this.getOctave() }, tonicPC); + let tonic = tonal$1.Note.midi(tonicNote); + let outPitches = []; + for (let pitchNote of pitches) { + let pitch = tonal$1.Note.midi(pitchNote); + if (pitch - tonic >= 6) + pitch -= 12; + outPitches.push(tonal$1.Note.fromMidi(pitch)); + } + return outPitches; + } + static getAnchorChord(anchor, songIterator, currentTime) { + let anchorChord; + switch (anchor) { + case 'KEY': { + anchorChord = songIterator.song.getTransposedKey(); + } + case 'NEXT': { + let nextMeasure = songIterator.getRelative(1); + if (nextMeasure) { + anchorChord = nextMeasure.beats[0].chord; + } + else { + anchorChord = songIterator.song.getTransposedKey(); + } + } + case 'STEP': + case 'ARPEGGIATE': + default: { + // crawl backward through this measure to get the last set beat + let lastSetBeat = Math.floor(currentTime); + let iteratorMeasure = songIterator.getRelative(0); + if (!iteratorMeasure) + break; + do { + const beat = iteratorMeasure.beats[lastSetBeat]; + anchorChord = beat && beat.chord; + lastSetBeat--; + } while (!anchorChord); + } + } + return this.normalizeChord(anchorChord); + } + static anchorChordToRoot(anchorChord, degree, octave) { + let anchorTonic = tonal$1.Chord.tokenize(anchorChord)[0]; + let anchorScaleName = this.chordToScaleName(anchorChord); + let scalePCs = tonal$1.Scale.notes(anchorTonic, anchorScaleName); + let rootPC = scalePCs[degree - 1]; + return tonal$1.Note.from({ oct: octave }, rootPC); + } + getAnchorData(songIterator) { + let anchorChord = MelodicBeatLiteral.getAnchorChord(this.pitch.anchor, songIterator, this.getTime()); + let root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, this.pitch.degree, this.getOctave()); + return [anchorChord, root]; + } + getPitches(songIterator) { + let [anchorChord, root] = this.getAnchorData(songIterator); + let pitches; + if (this.pitch.chord) { + // this feels extremely incorrect + // why would anyone need it to work this way + let anchorChordType = tonal$1.Chord.tokenize(anchorChord)[1]; + pitches = tonal$1.Chord.notes(root, anchorChordType); + } + else { + pitches = [root]; + } + if (this.scope.vars.get('invertible')) { + pitches = this.handleInversion(songIterator, pitches); + } + return pitches; + } + /** + * Returns true if the beat is anchored via STEP or ARPEGGIATE + * @returns {boolean} + */ + isDynamic() { + return ['STEP', 'ARPEGGIATE'].includes(this.pitch.anchor); + } + getOctave() { + if (this.octave === 'inherit') { + return this.scope.vars.get('octave'); + } + else { + return this.octave; + } + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + if (this.time.flag === 'STACCATO') { + return Math.min(0.25, duration); + } + else { + return duration; + } + } + getVolume() { + let volume = this.scope.vars.get('volume'); + if (this.time.flag === 'ACCENTED') + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let notes = new NoteSet(); + let time = this.getTime(); // @TODO: this varies with rolling + let pitches = this.getPitches(songIterator); + let duration = this.getDuration(); // @TODO: this varies with rolling + let volume = this.getVolume(); + for (let pitch of pitches) { + notes.push(new Note({ + time: time, + pitch: pitch, + duration: duration, + volume: volume + })); + } + return notes; + } +} +class DrumBeatLiteral { + constructor(opts) { + this.time = opts.time; + this.accented = opts.accented || false; + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + return this.time; + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + return duration; + } + getVolume() { + let volume = this.scope.vars.get('volume'); + if (this.accented) + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let time = this.getTime(); + let duration = this.getDuration(); + let volume = this.getVolume(); + return new NoteSet(new Note({ + time: time, + pitch: AwaitingDrum, + duration: duration, + volume: volume + })); + } +} + +let definitions = new Map(); +/** + * Make an assertion about argument count and types. + * @param {string} identifier The function name. + * @param {Array} args The arguments passed to the function. + * @param {Array.} types Array of the types (typeof) or classes + * (instanceof) to expect. + * @param {Scope} scope The scope, for error logging. + */ +function assertArgTypes(identifier, args, types, scope) { + if (types == '*') + return; + if (args.length != types.length) { + throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, scope); + } + for (let i in args) { + if (types[i] == '*') + continue; + let arg = args[i]; + if (arg instanceof FunctionCall) { + arg = arg.returns; + if (arg == '*') { + continue; // what's the correct functionality here? cry? + } + else if (typeof types[i] == 'string') { + if (arg != types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); + } + } + else { + if (arg != types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); + } + } + } + else { + if (typeof types[i] == 'string') { + if (typeof arg != types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); + } + } + else { + if (!(arg instanceof types[i])) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); + } + } + } + } +} +/** + * Make an assertion about the scope in which the function is called. + * @param {string} identifier The function's name. + * @param {string='no-meta'} goalscope One of 4 string options: + * - 'meta': the function throws if it's called outside a @meta block. + * - 'options': the function throws if it's called outside an @options block. + * - 'no-config': the function throws if it's called inside a @meta or @options + * block, but runs anywhere else that the parser will let you call a function. + * - 'pattern': the function throws if called outside a pattern scope. + * - 'no-meta' (default): the function throws if it's called inside a @meta + * block, but runs anywhere else that the parser will let you call a function. + * @param {Scope} scope The calling scope. + */ +function assertScope(identifier, goalscope = 'no-meta', scope) { + if (goalscope == 'meta') { + if (scope.type != '@meta') { + throw new FunctionScopeError(`Function "${identifier}" must only be called within a @meta block."`, scope); + } + } + else if (goalscope == 'options') { + if (scope.type != '@options') { + throw new FunctionScopeError(`Function "${identifier}" must only be called within an @options block."`, scope); + } + } + else if (goalscope == 'no-config') { + // ensure that config blocks can be resolved at compile time + if (scope.type == '@meta' || scope.type == '@options') { + throw new FunctionScopeError(`Function "${identifier}" must not be called within a @meta or @options block."`, scope); + } + } + else if (goalscope == 'pattern') { + if (scope.type != 'PatternExpressionGroup') { + throw new FunctionScopeError(`Function "${identifier}" must only be called within a @pattern block."`, scope); + } + // @TODO: what about @pattern foo private() -- makes no sense but yea + } + else if (goalscope == 'no-meta') { + if (scope.type == '@meta') { + throw new FunctionScopeError(`Function "${identifier}" must not be called within a @meta block."`, scope); + } + } +} +/** + * Define a function. + * @param {string} identifier The name of the function. + * @param {Object} opts Options passed. See below. + * @param {Array.|string='*'} opts.types If set, throw error + * unless the arguments passed to the function map to these. Can be strings + * (typeof) or classes (instanceof), or the single string '*' to accept + * anything. See assertArgTypes above. + * @param {string='no-meta'} opts.scope Throw error unless the calling + * scope matches. See assertScope above. + * @param {string|Function|Nil='*'} opts.returns The return type. If set to '*' + * it may return anything (for example, choose() returns one of whatever's + * passed to it regardless of type). + * @param {Function} func The function to run. It's passed 3 arguments: + * - args: an array of the arguments passed in the Playback function call. + * - scope: the calling scope. So it can set in scope.vars. + * - argErr: a function. If the function does further testing on its + * arguments and there's an issue, pass this the error message and it throws. + */ +let define$1 = function (identifier, opts, func) { + let definition = { + types: opts.types || '*', + returns: opts.returns || '*', + scope: opts.scope || 'no-meta', + execute: (args, songIterator, scope) => { + let argErr = message => { + throw new FunctionArgumentsError(message, scope); + }; + return func(args, songIterator, scope, argErr); + } + }; + definitions.set(identifier, definition); +}; +/** + * Quickly define a single-argument function that simply sets a var of the same + * name in its parent scope. + * @param {string} identifier The name of the function. + * @param {string|Function} type Throw unless the argument is of this type (see + * assertArgTypes above). + * @param {?string=null} goalscope Throw error unless the calling scope matches. + * See assertScope above. + */ +let defineVar = function (identifier, type, goalscope = null) { + let opts = { + types: [type], + scope: goalscope, + returns: Nil + }; + define$1(identifier, opts, (args, songIterator, scope, argErr) => { + scope.vars.set(identifier, args[0]); + return Nil; + }); +}; +/** + * Quickly define a function that sets a a var of the same name in its parent + * scope. If it has 0 args it sets the var to true, if it has 1 boolean arg + * it sets the var to that. + * @param {string} identifier The name of the function. + * @param {?string=null} goalscope Throw error unless the calling scope matches. + * See assertScope above. + */ +let defineBoolean = function (identifier, goalscope = null) { + let opts = { + types: '*', + scopes: goalscope, + returns: Nil + }; + define$1(identifier, opts, (args, songIterator, scope, argErr) => { + if (args.length) { + assertArgTypes(identifier, args, ['boolean'], scope); + scope.vars.set(identifier, args[0]); + } + else { + scope.vars.set(identifier, true); + } + return Nil; + }); +}; +/*********** ACTUAL FUNCTION DEFINITIONS ***********/ +/*** @meta functions ***/ +defineVar('name', 'string', 'meta'); +defineVar('author', 'string', 'meta'); +defineVar('description', 'string', 'meta'); +defineVar('playback-version', 'number', 'meta'); +/*** @options functions ***/ +define$1('time-signature', { + types: ['number', 'number'], + scope: 'options', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (!Number.isInteger(Math.log2(args[1]))) { + argErr('Argument 2 of "time-signature" must be a power of 2.'); + } + scope.vars.set('time-signature', [args[0], args[1]]); + return Nil; +}); +defineBoolean('swing', 'options'); +/*** anywhere but @meta functions ***/ +define$1('volume', { + types: ['number'], + scope: 'no-meta', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (args[0] < 0 || args[0] > 1) { + argErr('Argument 1 of "volume" must be in range 0-1 (inclusive).'); + } + scope.vars.set('volume', args[0]); + return Nil; +}); +defineBoolean('invertible', 'no-meta'); +define$1('octave', { + types: ['number'], + scope: 'no-meta', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { + argErr('Argument 1 of "octave" must be an integer 0-9.'); + } + scope.vars.set('octave', args[0]); + return Nil; +}); +/*** anywhere but config functions (strictly dynamic functions) ***/ +define$1('choose', { + types: '*', + scope: 'no-config', + returns: '*' +}, (args, songIterator, scope, argErr) => { + let nonNilArgs = args.filter(arg => arg !== Nil); + if (nonNilArgs.length) { + let index = Math.floor(Math.random() * nonNilArgs.length); + return nonNilArgs[index]; + } + else { + return Nil; + } +}); +let anchorOrNumberToChordAndRoot = function (arg, songIterator) { + let anchorChord, root; + if (typeof arg == 'number') { + anchorChord = MelodicBeatLiteral.getAnchorChord(null, songIterator, 1); + root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, arg, 4); + } + else if (arg.anchor) { + anchorChord = MelodicBeatLiteral.getAnchorChord(arg.anchor, songIterator, 1); + root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, 1, 4); + } + return [anchorChord, root]; +}; +define$1('progression', { + types: '*', + scope: 'no-config', + returns: 'boolean' +}, (args, songIterator, scope, argErr) => { + for (let i in args) { + let arg = args[i]; + let [, goal] = anchorOrNumberToChordAndRoot(arg, songIterator); + if (!goal) { + argErr('Arguments of "progression" must be numbers or anchors.'); + } + let actualMeasure = songIterator.getRelative(Number(i)); + if (!actualMeasure) + return false; + let actualChord = MelodicBeatLiteral.normalizeChord(actualMeasure.beats[0].chord); + let actual = MelodicBeatLiteral.anchorChordToRoot(actualChord, 1, 4); + if (actual != goal) + return false; + } + return true; +}); +define$1('in-scale', { + types: '*', + scope: 'no-config', + returns: 'boolean' +}, (args, songIterator, scope, argErr) => { + let [, note] = anchorOrNumberToChordAndRoot(args[0], songIterator); + let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); + if (!note || !goalChord) { + argErr('Arguments of "in-scale" must be numbers or anchors.'); + } + let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); + let goalScale = tonal$1.Scale.notes(goalTonic, goalScaleName); + return goalScale.includes(note); +}); +define$1('beat-defined', { + types: ['number'], + scope: 'no-config', + returns: 'boolean' +}, (args, songIterator, scope, argErr) => { + let measure = songIterator.getRelative(0); + if (!measure) + return false; + return measure.beats[args[0]].chord !== null; +}); +/*** pattern-only functions ***/ +defineBoolean('private', 'pattern'); +defineVar('length', 'number', 'pattern'); +define$1('chance', { + types: ['number'], + scope: 'pattern', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (args[0] < 0 || args[0] > 1) { + argErr('Argument 1 of "chance" must be in range 0-1 (inclusive).'); + } + scope.vars.set('chance', args[0]); + return Nil; +}); + +/** + * If the value is a FunctionCall, call it and return the returned value. + * Otherwise, return the value itself. + * @private + */ // @TODO: if this is needed elsewhere, put it somewhere useful. +class FunctionCall { + /** + * @constructor + * @param {string} identifier The name of the function. Ideally it should + * match the name of one of the functions in function_data.js + */ + constructor(identifier, args) { + this.identifier = identifier; + this.definition = definitions.get(identifier); + this.args = args; + this.scope = null; + } + init(scope) { + this.scope = scope; + if (!this.definition) { + throw new FunctionNameError(this.identifier, this.scope); + } + this.returns = this.definition.returns; + assertScope(this.identifier, this.definition.scope, this.scope); + this.args.forEach(arg => { + if (arg.init) + arg.init(scope); + }); + assertArgTypes(this.identifier, this.args, this.definition.types, this.scope); + } + link(ASTs, parentStyle, parentTrack) { + this.args.forEach(arg => { + if (arg.link) + arg.link(ASTs, parentStyle, parentTrack); + }); + } + execute(songIterator) { + if (!this.scope) + throw new Error('function not initialized :('); + let evaluatedArgs = this.args.map(arg => { + if (arg.execute) { + return arg.execute(songIterator); + } + else { + return arg; + } + }); + let returnValue = this.definition.execute(evaluatedArgs, songIterator, this.scope); + if (returnValue === undefined) { + throw new Error(`Function "${this.identifier}" can return undefined`); + } + return returnValue; + } +} + +class PatternExpressionGroup extends Scope { + constructor(expressions) { + super(); + this.type = 'PatternExpressionGroup'; + this.name = '@pattern()'; + this.defaultVars.set('private', false); + this.defaultVars.set('chance', 1); + this.expressions = expressions; + this.functionCalls = []; + this.nonFunctionCallExpressions = []; + } + init(scope, patternStatement = null) { + super.init(scope); + this.patternStatement = patternStatement; + if (this.patternStatement) { + this.name = `@pattern(${this.patternStatement})`; + } + this.expressions.forEach(expression => { + if (expression.init) { + expression.init(this); + } + else { + throw ['expression not initialized:', expression]; + } + if (expression instanceof FunctionCall) { + this.functionCalls.push(expression); + } + else { + this.nonFunctionCallExpressions.push(expression); + } + }); + } + link(ASTs, parentStyle, parentTrack) { + this.expressions.forEach(expression => { + expression.link(ASTs, parentStyle, parentTrack); + }); + } + execute(songIterator, callerIsTrack = false) { + this.inherit(); + let beats = Nil; + for (let function_call of this.functionCalls) { + let return_value = function_call.execute(songIterator); + if (return_value instanceof NoteSet) { + if (beats !== Nil) { + throw new TooManyBeatsError(this); + } + beats = return_value; + } + } + if (callerIsTrack && this.vars.get('private') === true) { + return Nil; // if it's private we can give up now + } + for (let expression of this.nonFunctionCallExpressions) { + if (expression.execute) { + expression = expression.execute(songIterator); + } + if (expression instanceof NoteSet) { + if (beats !== Nil) { + throw new TooManyBeatsError(this); + } + beats = expression; + } + } + return beats; + } +} +class PatternStatement extends PatternExpressionGroup { + constructor(opts) { + if (opts.expression instanceof PatternExpressionGroup) { + // unroll the redundant expression group + super(opts.expression.expressions); + } + else { + super([opts.expression]); + } + this.identifier = opts.identifier; + this.condition = (opts.condition !== undefined) ? opts.condition : null; + } + getChance() { + return this.vars.get('chance'); + } + link(ASTs, parentStyle, parentTrack) { + super.link(ASTs, parentStyle, parentTrack); + if (this.condition && this.condition.link) { + this.condition.link(ASTs, parentStyle, parentTrack); + } + } + init(scope) { + super.init(scope); + if (this.condition && this.condition.init) + this.condition.init(this); + } + execute(songIterator, callerIsTrack = false) { + if (this.condition) { + let condition_value; + if (this.condition.execute) { + condition_value = this.condition.execute(songIterator); + } + else { + condition_value = this.condition; + } + if (cast_bool(condition_value) === false) + return Nil; + } + return super.execute(songIterator, callerIsTrack); + } +} +class PatternCall { + constructor(opts) { + this.import = opts.import || null; + this.track = opts.track || null; + this.pattern = opts.pattern; + this.scope = null; + this.patternStatement = null; + this.prettyprintname = (this.import || 'this') + '.' + + (this.track || 'this') + '.' + + this.pattern; + } + getChance() { + return this.patternStatement.getChance()(); + } + init(scope) { + this.scope = scope; + } + link(ASTs, parentStyle, parentTrack) { + let ast; + if (this.import === null) { + ast = parentStyle; + } + else { + // get path name of style + let importPath = parentStyle.importedStyles.get(this.import); + ast = ASTs.get(importPath); + if (!ast) + throw new NoSuchStyleError(this.import, this); + } + let track; + if (this.track === null) { + track = parentTrack; + } + else { + track = ast.tracks.get(this.track); + if (!track) + throw new NoSuchTrackError(this.import || 'this', this.track || 'this', this); + } + let patternStatement = track.patterns.get(this.pattern); + if (!patternStatement) + throw new NoSuchPatternError(this.import || 'this', this.track || 'this', this.pattern, this); + this.patternStatement = patternStatement; + } + execute(songIterator) { + // called patternStatement ignores private() + return this.patternStatement.execute(songIterator); + } +} +class JoinedPatternExpression { + constructor(patterns) { + this.patterns = patterns; + } + init(scope) { + this.scope = scope; + this.patterns.forEach(pattern => { + if (pattern.init) + pattern.init(scope); + }); + } + link(ASTs, parentStyle, parentTrack) { + this.patterns.forEach(pattern => { + pattern.link(ASTs, parentStyle, parentTrack); + }); + } + execute(songIterator) { + let noteSets = []; + for (let pattern of this.patterns) { + if (pattern.execute) { + pattern = pattern.execute(songIterator); + } + if (pattern instanceof NoteSet) { + noteSets.push(pattern); + } + } + if (noteSets.length) { + return (new NoteSet()).concat(...noteSets); + } + else { + return Nil; + } + } +} + +class TrackStatement extends Scope { + constructor(opts) { + super(); + this.name = opts.identifier; + this.type = '@track'; + this.defaultVars.set('octave', 4); + this.defaultVars.set('volume', 1); + this.defaultVars.set('private', false); + this.instrument = opts.instrument; + this.identifier = opts.identifier; + this.members = opts.members; + } + init(scope) { + super.init(scope); + this.functionCalls = []; + this.patterns = new Map(); + this.patternCalls = []; + this.members.forEach(member => { + // initialize them all now, var inheritence is handled during execution + member.init(this); + if (member instanceof FunctionCall) { + this.functionCalls.push(member); + } + else if (member instanceof PatternStatement) { + this.patterns.set(member.identifier, member); + } + else if (member instanceof PatternCall) { + this.patternCalls.push(member); + } + }); + } + link(ASTs, parentStyle) { + for (let patternCall of this.patternCalls) { + patternCall.link(ASTs, parentStyle, this); + this.patterns.set(patternCall.prettyprintname, patternCall); + } + for (let [, pattern] of this.patterns) { + pattern.link(ASTs, parentStyle, this); + } + } + execute(songIterator) { + this.inherit(); + console.log(`executing TrackStatement "${this.name}"`); + this.functionCalls.forEach(function_call => { + function_call.execute(songIterator); + }); + // weighted random picking + // https://stackoverflow.com/a/4463613/1784306 + // I don't really understand the above explanation, this is probs wrong + let totalWeight = 0; + let weightedOptions = []; + for (let [patternname, pattern] of this.patterns) { + console.log(`- pattern "${patternname}":`); + // true = I'm the instrument so if you're private return Nil + let result = pattern.execute(songIterator, true); + console.log(' - Result:', result); + // @TODO: handle multi-measure patterns (via locks?) + if (result !== Nil) { + for (let note of result) { + if (note.pitch === AwaitingDrum) { + throw new DrumBeatInMelodicBeatGroupError(pattern); + } + } + let chance = pattern.getChance(); + weightedOptions.push({ + noteSet: result, + lower: totalWeight, + upper: totalWeight + chance + }); + totalWeight += chance; + } + } + // binary search would make sense here if I expected more items + let goal = Math.random() * totalWeight; + for (let option of weightedOptions) { + if (option.lower <= goal && goal <= option.upper) { + console.log(' - Final result:', option.noteSet); + return option.noteSet; + } + } + console.log(' - Final result:', Nil); + return Nil; + } +} +class TrackCall { + constructor(opts) { + this.import = opts.import; + this.track = opts.track; + this.trackStatement = null; // will be set by the loader. + } + execute(songIterator) { + this.trackStatement.execute(songIterator); + } +} + +class GlobalScope extends Scope { + constructor(statements) { + super(); + this.name = 'global'; + this.type = 'global'; + this.statements = statements; + } + init() { + // set some default values + this.vars.set('time-signature', [4, 4]); + this.vars.set('tempo', 120); + this.tracks = new Map(); + this.metaStatements = []; + // @TODO: stop circular dependencies? cache them and mark one as mom + this.importedStyles = new Map(); + this.trackCalls = []; + this.dependencies = []; + for (let statement of this.statements) { + if (statement instanceof MetaStatement + || statement instanceof OptionsStatement) { + // @TODO: make sure there's exactly 1 meta block + this.metaStatements.push(statement); + } + else if (statement instanceof ImportStatement) { + this.importedStyles.set(statement.identifier, statement.path); + this.dependencies.push(statement.path); + } + else if (statement instanceof TrackStatement) { + this.tracks.set(statement.name, statement); + } + else if (statement instanceof TrackCall) { + this.trackCalls.push(statement); + } + } + // handle meta blocks first since they set variables in own scope + this.metaStatements.forEach(statement => statement.init(this)); + // -- handle importing before statements -- + this.tracks.forEach(statement => statement.init(this)); + } + link(ASTs) { + for (let trackCall of this.trackCalls) { + // get path name of style + let importPath = this.importedStyles.get(trackCall.import); + let ast = ASTs.get(importPath); + if (!ast) + throw new NoSuchStyleError(trackCall.import, this); + let trackStatement = ast.tracks.get(trackCall.track); + if (!trackStatement) + throw new NoSuchTrackError(trackCall.import, trackCall.track, this); + //trackCall.trackStatement = trackStatement; + this.tracks.set(`${trackCall.import}.${trackCall.track}`, trackStatement); + } + for (let [, track] of this.tracks) { + track.link(ASTs, this); + } + } + execute(songIterator) { + let trackNoteMap = new Map(); + for (let [, track] of this.tracks) { + let trackNotes = track.execute(songIterator); + if (trackNotes !== Nil) + trackNoteMap.set(track.instrument, trackNotes); + } + return trackNoteMap; + } + getInstruments() { + let instruments = new Set(); + for (let [, track] of this.tracks) { + instruments.add(track.instrument); + } + return instruments; + } +} + +class AnchorArgument { + constructor(anchor) { + this.anchor = anchor; + } +} +class BooleanOperator { + constructor(...args) { + this.args = args; + } + link(ASTs, parentStyle, parentTrack) { + this.args.forEach(arg => { + if (arg.link) + arg.link(ASTs, parentStyle, parentTrack); + }); + } + init(scope) { + this.scope = scope; + this.args.forEach(arg => { + if (arg.init) + arg.init(scope); + }); + } + resolve_args(songIterator) { + return this.args.map(arg => { + if (arg.execute) { + return arg.execute(songIterator); + } + else { + return arg; + } + }); + } +} +class BooleanNot extends BooleanOperator { + constructor(...args) { + super(...args); + } + execute(songIterator) { + let args = this.resolve_args(songIterator); + return !cast_bool(args[0]); + } +} +class BooleanAnd extends BooleanOperator { + constructor(...args) { + super(...args); + } + execute(songIterator) { + // sorry no short-circuiting because this code is prettier + // @TODO: add short-circuiting if this actually makes it too slow + let args = this.resolve_args(songIterator); + return cast_bool(args[0]) && cast_bool(args[1]); + } +} +class BooleanOr extends BooleanOperator { + constructor(...args) { + super(...args); + } + execute(songIterator) { + let args = this.resolve_args(songIterator); + return cast_bool(args[0]) || cast_bool(args[1]); + } +} + +class BeatGroupLiteral { + constructor(measures) { + this.measures = measures; + this.scope = null; + } + init(scope) { + this.scope = scope; + this.measures.forEach((measure, i) => measure.init(scope, this, i)); + } + link() { return; } + execute(songIterator) { + let joinedMeasures = new NoteSet(); + for (let i = 0; i < this.measures.length; i++) { + let offset = i * 4; // @TODO: pull in actual meter somehow + let measureNotes = this.measures[i].execute(songIterator); + if (measureNotes === Nil) + return Nil; // lets a/s abort the beatgroup + for (let measureNote of measureNotes) { + measureNote.time += offset; + joinedMeasures.push(measureNote); + } + } + return joinedMeasures; + } + getNextStaticBeatRoot(measureIndex, beatIndex, songIterator) { + // first, try every subsequent beat in the beatGroup + // (including subsequent measures) + let measure, beat; + while (measure = this.parentBeatGroup.measures[measureIndex++]) { + while (beat = measure.beats[++beatIndex]) { + if (!beat.isDynamic()) { + return beat.getAnchorData(songIterator)[1]; + } + } + beatIndex = -1; + } + // if there are no non-dynamic beats in the rest of the beat-group, return + // the first note of the next measure (@TODO: could be multiple measures + // later if it's a multi-measure beatgroup) + // @TODO: wtf? + const nextMeasure = songIterator.getRelative(1); + return MelodicBeatLiteral.normalizeChord(nextMeasure && nextMeasure.beats[0].chord); + } +} +class Measure { + constructor(beats) { + this.beats = beats; + this.beatsPerMeasure = null; + this.scope = null; + } + calculateDurationAfter(beatIndex) { + let currentBeat = this.beats[beatIndex]; + let currentBeatTime = currentBeat.getTime(); + let nextBeatTime; + if (beatIndex + 1 >= this.beats.length) { + nextBeatTime = this.beatsPerMeasure + 1; + } + else { + let nextBeat = this.beats[beatIndex + 1]; + nextBeatTime = nextBeat.getTime(); + } + return nextBeatTime - currentBeatTime; + } + getNextStaticBeatRoot(beatIndex, songIterator) { + return this.parentBeatGroup.getNextStaticBeatRoot(this.indexInBeatGroup, beatIndex, songIterator); + } + init(scope, parentBeatGroup, indexInBeatGroup) { + this.scope = scope; + this.parentBeatGroup = parentBeatGroup; + this.indexInBeatGroup = indexInBeatGroup; + this.beatsPerMeasure = this.scope.vars.get('time-signature')[0]; + // @TODO does this need more math? + this.beats.forEach((beat, i) => { + beat.init(scope, this, i); + }); + } + execute(songIterator) { + // clear cached notes (used for STEP/ARPEGGIATE interpolation) + for (let beat of this.beats) { + if (beat instanceof MelodicBeatLiteral) + beat.cachedAnchor = null; + } + // each beat returns a NoteSet since it could be a chord or whatever + let joined = new NoteSet(); + for (let beat of this.beats) { + let notes = beat.execute(songIterator); + if (notes === Nil) + return Nil; // lets a and s abort the beatgroup. + joined.push(...notes); + } + return joined; + } +} +class DrumBeatGroupLiteral { + constructor(drum, beatGroup) { + this.drum = drum; + this.beatGroup = beatGroup; // for now there's no diff in functionality... + // @TODO make sure our beats are all drummy + } + init(scope) { + this.scope = scope; + if (this.beatGroup.init) + this.beatGroup.init(scope); + } + link() { return; } // @TODO: I think patterncalls are allowed here? + execute(songIterator) { + let notes = this.beatGroup.execute(songIterator); + for (let note of notes) { + if (note.pitch === AwaitingDrum) { + note.pitch = this.drum; // @TODO: convert to number? + } + else { + throw new MelodicBeatInDrumBeatGroupError(this.scope); + } + } + return notes; + } +} + +// Generated automatically by nearley, version 2.13.0 +// http://github.com/Hardmath123/nearley +function id(x) { return x[0]; } +let Lexer = lexer; +let ParserRules = [ + {"name": "main$macrocall$2", "symbols": ["TopLevelStatement"]}, + {"name": "main$macrocall$1$ebnf$1", "symbols": []}, + {"name": "main$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "main$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "main$macrocall$1$ebnf$1", "symbols": ["main$macrocall$1$ebnf$1", "main$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "main$macrocall$1", "symbols": ["main$macrocall$2", "main$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "main", "symbols": ["_?", "main$macrocall$1", "_?"], "postprocess": d => new GlobalScope(d[1])}, + {"name": "TopLevelStatement", "symbols": ["ConfigurationStatement"], "postprocess": id}, + {"name": "TopLevelStatement", "symbols": ["ImportStatement"], "postprocess": id}, + {"name": "TopLevelStatement", "symbols": ["TrackStatement"], "postprocess": id}, + {"name": "TopLevelStatement", "symbols": ["TrackCallStatement"], "postprocess": id}, + {"name": "ConfigurationStatement", "symbols": [{"literal":"@meta"}, "_?", {"literal":"{"}, "_?", "ConfigurationList", "_?", {"literal":"}"}], "postprocess": d => new MetaStatement(d[4])}, + {"name": "ConfigurationStatement", "symbols": [{"literal":"@options"}, "_?", {"literal":"{"}, "_?", "ConfigurationList", "_?", {"literal":"}"}], "postprocess": d => new OptionsStatement(d[4])}, + {"name": "ConfigurationList$macrocall$2", "symbols": ["FunctionCallExpression"]}, + {"name": "ConfigurationList$macrocall$1$ebnf$1", "symbols": []}, + {"name": "ConfigurationList$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "ConfigurationList$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "ConfigurationList$macrocall$1$ebnf$1", "symbols": ["ConfigurationList$macrocall$1$ebnf$1", "ConfigurationList$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "ConfigurationList$macrocall$1", "symbols": ["ConfigurationList$macrocall$2", "ConfigurationList$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "ConfigurationList", "symbols": ["ConfigurationList$macrocall$1"], "postprocess": id}, + {"name": "ImportStatement", "symbols": [{"literal":"@import"}, "_", "StringLiteral", "_", {"literal":"as"}, "_", "Identifier"], "postprocess": d => new ImportStatement(d[2], d[6])}, + {"name": "TrackStatement$macrocall$2", "symbols": ["TrackMember"]}, + {"name": "TrackStatement$macrocall$1$ebnf$1", "symbols": []}, + {"name": "TrackStatement$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "TrackStatement$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "TrackStatement$macrocall$1$ebnf$1", "symbols": ["TrackStatement$macrocall$1$ebnf$1", "TrackStatement$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "TrackStatement$macrocall$1", "symbols": ["TrackStatement$macrocall$2", "TrackStatement$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "TrackStatement", "symbols": [{"literal":"@track"}, "_", "StringLiteral", "_", {"literal":"as"}, "_", "Identifier", "_?", {"literal":"{"}, "_?", "TrackStatement$macrocall$1", "_?", {"literal":"}"}], "postprocess": d => new TrackStatement({instrument: d[2], identifier: d[6], members: d[10]})}, + {"name": "TrackMember", "symbols": ["FunctionCallExpression"], "postprocess": id}, + {"name": "TrackMember", "symbols": ["PatternStatement"], "postprocess": id}, + {"name": "TrackMember", "symbols": ["PatternCallExpression"], "postprocess": id}, + {"name": "TrackCallStatement", "symbols": [{"literal":"@track"}, "_?", {"literal":"("}, "_?", "Identifier", {"literal":"."}, "Identifier", "_?", {"literal":")"}], "postprocess": d => new TrackCall({import: d[4], track: d[6]})}, + {"name": "PatternStatement", "symbols": [{"literal":"@pattern"}, "_", "Identifier", "_", "PatternConditional", "_?", "PatternExpression"], "postprocess": d => new PatternStatement({identifier: d[2], expression: d[6], condition: d[4]})}, + {"name": "PatternStatement", "symbols": [{"literal":"@pattern"}, "_", "Identifier", "_", "PatternExpression"], "postprocess": d => new PatternStatement({identifier: d[2], expression: d[4]})}, + {"name": "PatternConditional", "symbols": [{"literal":"if"}, "_?", {"literal":"("}, "_?", "FunctionCallArgument", "_?", {"literal":")"}], "postprocess": d => d[4]}, + {"name": "PatternExpression", "symbols": ["PatternExpression_NoJoin"], "postprocess": id}, + {"name": "PatternExpression", "symbols": ["JoinedPatternExpression"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["PatternExpressionGroup"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["BeatGroupLiteral"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["DrumBeatGroupLiteral"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["FunctionCallExpression"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["PatternCallExpression"], "postprocess": id}, + {"name": "PatternExpressionGroup$macrocall$2", "symbols": ["PatternExpression"]}, + {"name": "PatternExpressionGroup$macrocall$1$ebnf$1", "symbols": []}, + {"name": "PatternExpressionGroup$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "PatternExpressionGroup$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "PatternExpressionGroup$macrocall$1$ebnf$1", "symbols": ["PatternExpressionGroup$macrocall$1$ebnf$1", "PatternExpressionGroup$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "PatternExpressionGroup$macrocall$1", "symbols": ["PatternExpressionGroup$macrocall$2", "PatternExpressionGroup$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "PatternExpressionGroup", "symbols": [{"literal":"{"}, "_?", "PatternExpressionGroup$macrocall$1", "_?", {"literal":"}"}], "postprocess": d => new PatternExpressionGroup(d[2])}, + {"name": "PatternCallExpression", "symbols": [{"literal":"@pattern"}, "_?", {"literal":"("}, "_?", "Identifier", "_?", {"literal":")"}], "postprocess": d => new PatternCall({pattern: d[4]})}, + {"name": "PatternCallExpression", "symbols": [{"literal":"@pattern"}, "_?", {"literal":"("}, "_?", "Identifier", {"literal":"."}, "Identifier", "_?", {"literal":")"}], "postprocess": d => new PatternCall({track: d[4], pattern: d[6]})}, + {"name": "PatternCallExpression", "symbols": [{"literal":"@pattern"}, "_?", {"literal":"("}, "_?", "Identifier", {"literal":"."}, "Identifier", {"literal":"."}, "Identifier", "_?", {"literal":")"}], "postprocess": d => new PatternCall({import: d[4], track: d[6], pattern: d[8]})}, + {"name": "JoinedPatternExpression$macrocall$2", "symbols": ["PatternExpression_NoJoin"]}, + {"name": "JoinedPatternExpression$macrocall$3", "symbols": [{"literal":"&"}]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_?", "JoinedPatternExpression$macrocall$3", "_?", "JoinedPatternExpression$macrocall$2"], "postprocess": d => d[3][0]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1", "symbols": ["JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$1"]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$2", "symbols": ["_?", "JoinedPatternExpression$macrocall$3", "_?", "JoinedPatternExpression$macrocall$2"], "postprocess": d => d[3][0]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1", "symbols": ["JoinedPatternExpression$macrocall$1$ebnf$1", "JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "JoinedPatternExpression$macrocall$1", "symbols": ["JoinedPatternExpression$macrocall$2", "JoinedPatternExpression$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "JoinedPatternExpression", "symbols": ["JoinedPatternExpression$macrocall$1"], "postprocess": d => new JoinedPatternExpression(d[0])}, + {"name": "FunctionCallExpression$macrocall$2", "symbols": ["FunctionCallArgument"]}, + {"name": "FunctionCallExpression$macrocall$1$ebnf$1", "symbols": []}, + {"name": "FunctionCallExpression$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "FunctionCallExpression$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "FunctionCallExpression$macrocall$1$ebnf$1", "symbols": ["FunctionCallExpression$macrocall$1$ebnf$1", "FunctionCallExpression$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "FunctionCallExpression$macrocall$1", "symbols": ["FunctionCallExpression$macrocall$2", "FunctionCallExpression$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, "_?", "FunctionCallExpression$macrocall$1", "_?", {"literal":")"}], "postprocess": d => new FunctionCall(d[0], d[4])}, + {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, {"literal":")"}], "postprocess": d => new FunctionCall(d[0], [])}, + {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["PatternExpression"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new AnchorArgument(d[0])}, + {"name": "FunctionCallArgument", "symbols": [{"literal":"not"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanNot(d[2])}, + {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"and"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanAnd(d[0], d[4])}, + {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"or"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanOr(d[0], d[4])}, + {"name": "BeatGroupLiteral", "symbols": [{"literal":"<"}, "_?", "MeasureGroup", "_?", {"literal":">"}], "postprocess": d => new BeatGroupLiteral(d[2])}, + {"name": "MeasureGroup$macrocall$2", "symbols": ["Measure"]}, + {"name": "MeasureGroup$macrocall$3", "symbols": [{"literal":"|"}]}, + {"name": "MeasureGroup$macrocall$1$ebnf$1", "symbols": []}, + {"name": "MeasureGroup$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_?", "MeasureGroup$macrocall$3", "_?", "MeasureGroup$macrocall$2"], "postprocess": d => d[3][0]}, + {"name": "MeasureGroup$macrocall$1$ebnf$1", "symbols": ["MeasureGroup$macrocall$1$ebnf$1", "MeasureGroup$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "MeasureGroup$macrocall$1", "symbols": ["MeasureGroup$macrocall$2", "MeasureGroup$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "MeasureGroup", "symbols": ["MeasureGroup$macrocall$1"], "postprocess": id}, + {"name": "Measure$macrocall$2", "symbols": ["MelodicBeatLiteral"]}, + {"name": "Measure$macrocall$1$ebnf$1", "symbols": []}, + {"name": "Measure$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "Measure$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "Measure$macrocall$1$ebnf$1", "symbols": ["Measure$macrocall$1$ebnf$1", "Measure$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "Measure$macrocall$1", "symbols": ["Measure$macrocall$2", "Measure$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "Measure", "symbols": ["Measure$macrocall$1"], "postprocess": d => new Measure(d[0])}, + {"name": "MelodicBeatLiteral", "symbols": ["BL_TimePart", {"literal":":"}, "BL_PitchPart", {"literal":":"}, "BL_OctavePart"], "postprocess": d => new MelodicBeatLiteral({time: d[0], pitch: d[2], octave: d[4]})}, + {"name": "MelodicBeatLiteral", "symbols": [{"literal":":"}, "BL_PitchPart", {"literal":":"}, "BL_OctavePart"], "postprocess": d => new MelodicBeatLiteral({pitch: d[1], octave: d[3]})}, + {"name": "MelodicBeatLiteral", "symbols": ["BL_TimePart", {"literal":":"}, "BL_PitchPart"], "postprocess": d => new MelodicBeatLiteral({time: d[0], pitch: d[2]})}, + {"name": "MelodicBeatLiteral", "symbols": [{"literal":":"}, "BL_PitchPart"], "postprocess": d => new MelodicBeatLiteral({pitch: d[1]})}, + {"name": "MelodicBeatLiteral", "symbols": ["DrumBeatLiteral"], "postprocess": id}, + {"name": "BL_TimePart", "symbols": ["NumericExpression"], "postprocess": d => ({time: d[0]})}, + {"name": "BL_TimePart", "symbols": ["BL_TP_Flag"], "postprocess": d => ({time: 'auto', flag: d[0]})}, + {"name": "BL_TimePart", "symbols": ["NumericExpression", "BL_TP_Flag"], "postprocess": d => ({time: d[0], flag: d[1]})}, + {"name": "BL_TP_Flag", "symbols": [{"literal":"s"}], "postprocess": d => 'STACCATO'}, + {"name": "BL_TP_Flag", "symbols": [{"literal":"a"}], "postprocess": d => 'ACCENTED'}, + {"name": "BL_PitchPart", "symbols": ["BL_PP_Degree"], "postprocess": id}, + {"name": "BL_PitchPart", "symbols": ["BL_PP_Chord"], "postprocess": id}, + {"name": "BL_PP_Degree", "symbols": ["NumberLiteral"], "postprocess": d => ({degree: d[0]})}, + {"name": "BL_PP_Degree", "symbols": ["BL_PP_Anchor"], "postprocess": d => ({anchor: d[0], degree: 1})}, + {"name": "BL_PP_Degree", "symbols": ["BL_PP_Anchor", "NumberLiteral"], "postprocess": d => ({anchor: d[0], degree: d[1]})}, + {"name": "BL_PP_Chord", "symbols": [{"literal":"c"}], "postprocess": d => ({chord: true, degree: 1})}, + {"name": "BL_PP_Chord", "symbols": ["BL_PP_Degree", {"literal":"c"}], "postprocess": d => ({chord: true, anchor: d[0].anchor, degree: d[0].degree})}, + {"name": "BL_PP_Chord", "symbols": [{"literal":"c"}, "BL_PP_Roll"], "postprocess": d => ({chord: true, roll: d[1], degree: 1})}, + {"name": "BL_PP_Chord", "symbols": ["BL_PP_Degree", {"literal":"c"}, "BL_PP_Roll"], "postprocess": d => ({chord: true, roll: d[2], anchor: d[0].anchor, degree: d[0].degree})}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"k"}], "postprocess": d => 'KEY'}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"n"}], "postprocess": d => 'NEXT'}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"s"}], "postprocess": d => 'STEP'}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"a"}], "postprocess": d => 'ARPEGGIATE'}, + {"name": "BL_PP_Roll", "symbols": [{"literal":"r"}], "postprocess": d => 'ROLL_UP'}, + {"name": "BL_PP_Roll", "symbols": [{"literal":"r"}, {"literal":"d"}], "postprocess": d => 'ROLL_DOWN'}, + {"name": "BL_OctavePart", "symbols": ["NumberLiteral"], "postprocess": id}, + {"name": "DrumBeatGroupLiteral", "symbols": ["StringLiteral", "_?", "BeatGroupLiteral"], "postprocess": d => new DrumBeatGroupLiteral(d[0], d[2])}, + {"name": "DrumBeatGroupLiteral", "symbols": ["StringLiteral", "_?", "FunctionCallExpression"], "postprocess": d => new DrumBeatGroupLiteral(d[0], d[2])}, + {"name": "DrumBeatLiteral", "symbols": ["NumberLiteral"], "postprocess": d => new DrumBeatLiteral({time: d[0]})}, + {"name": "DrumBeatLiteral", "symbols": ["NumberLiteral", {"literal":"a"}], "postprocess": d => new DrumBeatLiteral({time: d[0], accented: true})}, + {"name": "NumericExpression", "symbols": ["NE_addsub"], "postprocess": id}, + {"name": "NE_parens", "symbols": [{"literal":"("}, "NE_addsub", {"literal":")"}], "postprocess": d => d[1]}, + {"name": "NE_parens", "symbols": ["NumberLiteral"], "postprocess": id}, + {"name": "NE_muldiv", "symbols": ["NE_muldiv", {"literal":"*"}, "NE_parens"], "postprocess": d => (d[0] * d[2])}, + {"name": "NE_muldiv", "symbols": ["NE_muldiv", {"literal":"/"}, "NE_parens"], "postprocess": d => (d[0] / d[2])}, + {"name": "NE_muldiv", "symbols": ["NE_parens"], "postprocess": id}, + {"name": "NE_addsub", "symbols": ["NE_addsub", {"literal":"+"}, "NE_muldiv"], "postprocess": d => (d[0] + d[2])}, + {"name": "NE_addsub", "symbols": ["NE_addsub", {"literal":"-"}, "NE_muldiv"], "postprocess": d => (d[0] - d[2])}, + {"name": "NE_addsub", "symbols": ["NE_muldiv"], "postprocess": id}, + {"name": "Identifier", "symbols": [(lexer.has("identifier") ? {type: "identifier"} : identifier)], "postprocess": d => d[0].value}, + {"name": "NumberLiteral", "symbols": [(lexer.has("number") ? {type: "number"} : number)], "postprocess": d => Number(d[0].value)}, + {"name": "NumberLiteral", "symbols": [(lexer.has("beat_number") ? {type: "beat_number"} : beat_number)], "postprocess": d => Number(d[0].value)}, + {"name": "BooleanLiteral", "symbols": [(lexer.has("boolean") ? {type: "boolean"} : boolean)], "postprocess": d => Boolean(d[0].value)}, + {"name": "StringLiteral", "symbols": [(lexer.has("quoted_string") ? {type: "quoted_string"} : quoted_string)], "postprocess": d => d[0].value.slice(1, -1)}, + {"name": "_?$ebnf$1", "symbols": ["_"], "postprocess": id}, + {"name": "_?$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_?", "symbols": ["_?$ebnf$1"], "postprocess": () => null}, + {"name": "_", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": () => null}, + {"name": "_", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": () => null}, + {"name": "_$ebnf$1", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": id}, + {"name": "_$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$2$subexpression$1$ebnf$1", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": id}, + {"name": "_$ebnf$2$subexpression$1$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$2$subexpression$1", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$2$subexpression$1$ebnf$1"]}, + {"name": "_$ebnf$2", "symbols": ["_$ebnf$2$subexpression$1"]}, + {"name": "_$ebnf$2$subexpression$2$ebnf$1", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": id}, + {"name": "_$ebnf$2$subexpression$2$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$2$subexpression$2", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$2$subexpression$2$ebnf$1"]}, + {"name": "_$ebnf$2", "symbols": ["_$ebnf$2", "_$ebnf$2$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "_", "symbols": ["_$ebnf$1", "_$ebnf$2"], "postprocess": () => null}, + {"name": "_$ebnf$3", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": id}, + {"name": "_$ebnf$3", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$4$subexpression$1$ebnf$1", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": id}, + {"name": "_$ebnf$4$subexpression$1$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$4$subexpression$1", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$4$subexpression$1$ebnf$1"]}, + {"name": "_$ebnf$4", "symbols": ["_$ebnf$4$subexpression$1"]}, + {"name": "_$ebnf$4$subexpression$2$ebnf$1", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": id}, + {"name": "_$ebnf$4$subexpression$2$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$4$subexpression$2", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$4$subexpression$2$ebnf$1"]}, + {"name": "_$ebnf$4", "symbols": ["_$ebnf$4", "_$ebnf$4$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "_", "symbols": ["_$ebnf$3", "_$ebnf$4"], "postprocess": () => null} +]; +let ParserStart = "main"; +var grammar = { Lexer, ParserRules, ParserStart }; + +/** + * Parses a string into a set of possible abstract systax trees (ASTs) trees of + * objects representing the syntax of the file. + * @param {string} data The string to parse + * @return {Promise..} A promise that resolves to an array + * of parsings, each of which is an AST. (Ideally there should be 1 parsing.) + * + * See ast_nodes.js or the grammar itself for an idea of what the nodes in the + * tree might look like. + * @private + */ +function getPossibleParses(data) { + return __awaiter(this, void 0, void 0, function* () { + // Create a Parser object from our grammar. + // (I don't think you can reset the parser so make a new one each time) + const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar)); + try { + parser.feed(data); + return parser.results; + } + catch (err) { + // Because tabs screw up the formatting of SyntaxError messages. + err.message = err.message.replace(/\t/g, ' '); + throw err; + } + }); +} +/** + * Parse a string into an Abstract Syntax Tree (AST) -- a tree of objects + * representing the syntax of the file. + * @param {string} data The string to parse + * @return {Promise.} The Abstract Systax Tree (AST). + */ +function parse(data) { + return __awaiter(this, void 0, void 0, function* () { + const parses = yield getPossibleParses(data); + if (!parses.length) { + throw new SyntaxError('Something went wrong, input not parseable.'); + } + return parses[0]; + }); +} + +class PlaybackStyle { + /** + * Set the main ast (the one that plays all its instruments by default). + * @param {ast.GlobalScope} main the main ast + * @param {Map.} asts A map of asts by their path + */ + constructor(mainPath) { + this.mainPath = mainPath; + this.ASTs = new Map(); + this.initialized = false; + } + /** + * Parse each file, pull its dependencies, put it all in a cache, rinse and + * repeat. + * @private + */ + _loadDependencies() { + return __awaiter(this, void 0, void 0, function* () { + let pendingDependencies = [this.mainPath]; + let dependencyPath; + // @TODO: verify that dependencies have compatible time signature to main + while (dependencyPath = pendingDependencies.pop()) { + let rawfile; + try { + rawfile = yield load(dependencyPath); + } + catch (e) { + throw new Error(`Couldn't locate imported style "${dependencyPath}".`); + } + let ast = yield parse(rawfile); + this.ASTs.set(dependencyPath, ast); + ast.init(); + for (let newDependency of ast.dependencies) { + if (!this.ASTs.has(newDependency)) { + pendingDependencies.push(newDependency); + } + } + } + this.main = this.ASTs.get(this.mainPath); + }); + } + _link() { + this.main.link(this.ASTs); + } + /** + * Initialize the style, which includes loading dependencies and linking + * track/pattern calls. Must be called before compiling/playing. + */ + init() { + return __awaiter(this, void 0, void 0, function* () { + yield this._loadDependencies(); + this._link(); + this.initialized = true; + }); + } + /** + * Compile a song into a set of MIDI-like note instructions. + * @param {Song} song A Playback Song (notochord????) + * @returns {NoteSet.} An array-like object containing MIDI-like note + * instructions. + */ + compile(song) { + if (!this.initialized) { + throw new Error('PlayBack style must be initialized before compiling'); + } + let songIterator = song[Symbol.iterator](); + let instruments = this.getInstruments(); + let notes = new Map(); + let beatsPerMeasure = this.main.vars.get('time-signature')[0]; + let totalPastBeats = 0; + for (let instrument of instruments) + notes.set(instrument, new NoteSet()); + let nextValue; + while (nextValue = songIterator.next(), nextValue.done == false) { + let thisMeasureTracks = this.main.execute(songIterator); + for (let [instrument, thisMeasureNotes] of thisMeasureTracks) { + for (let note of thisMeasureNotes) { + note.time += totalPastBeats; + if (this.main.vars.get('swing')) { + let int_part = Math.floor(note.time); + let float_part = note.time - int_part; + if (float_part <= 0.5) { + float_part *= 2; + float_part = (2 / 3) * float_part; + } + else { + float_part = 2 * (float_part - 0.5); + float_part = (2 / 3) + ((1 / 3) * float_part); + } + note.time = int_part + float_part; + } + } + notes.get(instrument).push(...thisMeasureNotes); + } + totalPastBeats += beatsPerMeasure; + } + return notes; + } + getInstruments() { + return this.main.getInstruments(); + } +} + +let moduleDefs = {1:[function(require,module,exports){ + + var load = require('audio-loader'); + var player = require('sample-player'); + + /** + * Load a soundfont instrument. It returns a promise that resolves to a + * instrument object. + * + * The instrument object returned by the promise has the following properties: + * + * - name: the instrument name + * - play: A function to play notes from the buffer with the signature + * `play(note, time, duration, options)` + * + * + * The valid options are: + * + * - `format`: the soundfont format. 'mp3' by default. Can be 'ogg' + * - `soundfont`: the soundfont name. 'MusyngKite' by default. Can be 'FluidR3_GM' + * - `nameToUrl` : a function to convert from instrument names to URL + * - `destination`: by default Soundfont uses the `audioContext.destination` but you can override it. + * - `gain`: the gain of the player (1 by default) + * - `notes`: an array of the notes to decode. It can be an array of strings + * with note names or an array of numbers with midi note numbers. This is a + * performance option: since decoding mp3 is a cpu intensive process, you can limit + * limit the number of notes you want and reduce the time to load the instrument. + * + * @param {AudioContext} ac - the audio context + * @param {String} name - the instrument name. For example: 'acoustic_grand_piano' + * @param {Object} options - (Optional) the same options as Soundfont.loadBuffers + * @return {Promise} + * + * @example + * var Soundfont = require('sounfont-player') + * Soundfont.instrument('marimba').then(function (marimba) { + * marimba.play('C4') + * }) + */ + function instrument (ac, name, options) { + if (arguments.length === 1) return function (n, o) { return instrument(ac, n, o) } + var opts = options || {}; + var isUrl = opts.isSoundfontURL || isSoundfontURL; + var toUrl = opts.nameToUrl || nameToUrl; + var url = isUrl(name) ? name : toUrl(name, opts.soundfont, opts.format); + + return load(ac, url, { only: opts.only || opts.notes }).then(function (buffers) { + var p = player(ac, buffers, opts).connect(opts.destination ? opts.destination : ac.destination); + p.url = url; + p.name = name; + return p + }) + } + + function isSoundfontURL (name) { + return /\.js(\?.*)?$/i.test(name) + } + + /** + * Given an instrument name returns a URL to to the Benjamin Gleitzman's + * package of [pre-rendered sound fonts](https://github.com/gleitz/midi-js-soundfonts) + * + * @param {String} name - instrument name + * @param {String} soundfont - (Optional) the soundfont name. One of 'FluidR3_GM' + * or 'MusyngKite' ('MusyngKite' by default) + * @param {String} format - (Optional) Can be 'mp3' or 'ogg' (mp3 by default) + * @returns {String} the Soundfont file url + * @example + * var Soundfont = require('soundfont-player') + * Soundfont.nameToUrl('marimba', 'mp3') + */ + function nameToUrl (name, sf, format) { + format = format === 'ogg' ? format : 'mp3'; + sf = sf === 'FluidR3_GM' ? sf : 'MusyngKite'; + return 'https://gleitz.github.io/midi-js-soundfonts/' + sf + '/' + name + '-' + format + '.js' + } + + // In the 1.0.0 release it will be: + // var Soundfont = {} + var Soundfont = require('./legacy'); + Soundfont.instrument = instrument; + Soundfont.nameToUrl = nameToUrl; + + if (typeof module === 'object' && module.exports) module.exports = Soundfont; + if (typeof window !== 'undefined') window.Soundfont = Soundfont; + + },{"./legacy":2,"audio-loader":6,"sample-player":10}],2:[function(require,module,exports){ + + var parser = require('note-parser'); + + /** + * Create a Soundfont object + * + * @param {AudioContext} context - the [audio context](https://developer.mozilla.org/en/docs/Web/API/AudioContext) + * @param {Function} nameToUrl - (Optional) a function that maps the sound font name to the url + * @return {Soundfont} a soundfont object + */ + function Soundfont (ctx, nameToUrl) { + console.warn('new Soundfont() is deprected'); + console.log('Please use Soundfont.instrument() instead of new Soundfont().instrument()'); + if (!(this instanceof Soundfont)) return new Soundfont(ctx) + + this.nameToUrl = nameToUrl || Soundfont.nameToUrl; + this.ctx = ctx; + this.instruments = {}; + this.promises = []; + } + + Soundfont.prototype.onready = function (callback) { + console.warn('deprecated API'); + console.log('Please use Promise.all(Soundfont.instrument(), Soundfont.instrument()).then() instead of new Soundfont().onready()'); + Promise.all(this.promises).then(callback); + }; + + Soundfont.prototype.instrument = function (name, options) { + console.warn('new Soundfont().instrument() is deprecated.'); + console.log('Please use Soundfont.instrument() instead.'); + var ctx = this.ctx; + name = name || 'default'; + if (name in this.instruments) return this.instruments[name] + var inst = {name: name, play: oscillatorPlayer(ctx, options)}; + this.instruments[name] = inst; + if (name !== 'default') { + var promise = Soundfont.instrument(ctx, name, options).then(function (instrument) { + inst.play = instrument.play; + return inst + }); + this.promises.push(promise); + inst.onready = function (cb) { + console.warn('onready is deprecated. Use Soundfont.instrument().then()'); + promise.then(cb); + }; + } else { + inst.onready = function (cb) { + console.warn('onready is deprecated. Use Soundfont.instrument().then()'); + cb(); + }; + } + return inst + }; + + /* + * Load the buffers of a given instrument name. It returns a promise that resolves + * to a hash with midi note numbers as keys, and audio buffers as values. + * + * @param {AudioContext} ac - the audio context + * @param {String} name - the instrument name (it accepts an url if starts with "http") + * @param {Object} options - (Optional) options object + * @return {Promise} a promise that resolves to a Hash of { midiNoteNum: } + * + * The options object accepts the following keys: + * + * - nameToUrl {Function}: a function to convert from instrument names to urls. + * By default it uses Benjamin Gleitzman's package of + * [pre-rendered sound fonts](https://github.com/gleitz/midi-js-soundfonts) + * - notes {Array}: the list of note names to be decoded (all by default) + * + * @example + * var Soundfont = require('soundfont-player') + * Soundfont.loadBuffers(ctx, 'acoustic_grand_piano').then(function(buffers) { + * buffers[60] // => An corresponding to note C4 + * }) + */ + function loadBuffers (ac, name, options) { + console.warn('Soundfont.loadBuffers is deprecate.'); + console.log('Use Soundfont.instrument(..) and get buffers properties from the result.'); + return Soundfont.instrument(ac, name, options).then(function (inst) { + return inst.buffers + }) + } + Soundfont.loadBuffers = loadBuffers; + + /** + * Returns a function that plays an oscillator + * + * @param {AudioContext} ac - the audio context + * @param {Hash} defaultOptions - (Optional) a hash of options: + * - vcoType: the oscillator type (default: 'sine') + * - gain: the output gain value (default: 0.4) + * - destination: the player destination (default: ac.destination) + */ + function oscillatorPlayer (ctx, defaultOptions) { + defaultOptions = defaultOptions || {}; + return function (note, time, duration, options) { + console.warn('The oscillator player is deprecated.'); + console.log('Starting with version 0.9.0 you will have to wait until the soundfont is loaded to play sounds.'); + var midi = note > 0 && note < 129 ? +note : parser.midi(note); + var freq = midi ? parser.midiToFreq(midi, 440) : null; + if (!freq) return + + duration = duration || 0.2; + + options = options || {}; + var destination = options.destination || defaultOptions.destination || ctx.destination; + var vcoType = options.vcoType || defaultOptions.vcoType || 'sine'; + var gain = options.gain || defaultOptions.gain || 0.4; + + var vco = ctx.createOscillator(); + vco.type = vcoType; + vco.frequency.value = freq; + + /* VCA */ + var vca = ctx.createGain(); + vca.gain.value = gain; + + /* Connections */ + vco.connect(vca); + vca.connect(destination); + + vco.start(time); + if (duration > 0) vco.stop(time + duration); + return vco + } + } + + /** + * Given a note name, return the note midi number + * + * @name noteToMidi + * @function + * @param {String} noteName + * @return {Integer} the note midi number or null if not a valid note name + */ + Soundfont.noteToMidi = parser.midi; + + module.exports = Soundfont; + + },{"note-parser":8}],3:[function(require,module,exports){ + module.exports = ADSR; + + function ADSR(audioContext){ + var node = audioContext.createGain(); + + var voltage = node._voltage = getVoltage(audioContext); + var value = scale(voltage); + var startValue = scale(voltage); + var endValue = scale(voltage); + + node._startAmount = scale(startValue); + node._endAmount = scale(endValue); + + node._multiplier = scale(value); + node._multiplier.connect(node); + node._startAmount.connect(node); + node._endAmount.connect(node); + + node.value = value.gain; + node.startValue = startValue.gain; + node.endValue = endValue.gain; + + node.startValue.value = 0; + node.endValue.value = 0; + + Object.defineProperties(node, props); + return node + } + + var props = { + + attack: { value: 0, writable: true }, + decay: { value: 0, writable: true }, + sustain: { value: 1, writable: true }, + release: {value: 0, writable: true }, + + getReleaseDuration: { + value: function(){ + return this.release + } + }, + + start: { + value: function(at){ + var target = this._multiplier.gain; + var startAmount = this._startAmount.gain; + var endAmount = this._endAmount.gain; + + this._voltage.start(at); + this._decayFrom = this._decayFrom = at+this.attack; + this._startedAt = at; + + var sustain = this.sustain; + + target.cancelScheduledValues(at); + startAmount.cancelScheduledValues(at); + endAmount.cancelScheduledValues(at); + + endAmount.setValueAtTime(0, at); + + if (this.attack){ + target.setValueAtTime(0, at); + target.linearRampToValueAtTime(1, at + this.attack); + + startAmount.setValueAtTime(1, at); + startAmount.linearRampToValueAtTime(0, at + this.attack); + } else { + target.setValueAtTime(1, at); + startAmount.setValueAtTime(0, at); + } + + if (this.decay){ + target.setTargetAtTime(sustain, this._decayFrom, getTimeConstant(this.decay)); + } + } + }, + + stop: { + value: function(at, isTarget){ + if (isTarget){ + at = at - this.release; + } + + var endTime = at + this.release; + if (this.release){ + + var target = this._multiplier.gain; + var startAmount = this._startAmount.gain; + var endAmount = this._endAmount.gain; + + target.cancelScheduledValues(at); + startAmount.cancelScheduledValues(at); + endAmount.cancelScheduledValues(at); + + var expFalloff = getTimeConstant(this.release); + + // truncate attack (required as linearRamp is removed by cancelScheduledValues) + if (this.attack && at < this._decayFrom){ + var valueAtTime = getValue(0, 1, this._startedAt, this._decayFrom, at); + target.linearRampToValueAtTime(valueAtTime, at); + startAmount.linearRampToValueAtTime(1-valueAtTime, at); + startAmount.setTargetAtTime(0, at, expFalloff); + } + + endAmount.setTargetAtTime(1, at, expFalloff); + target.setTargetAtTime(0, at, expFalloff); + } + + this._voltage.stop(endTime); + return endTime + } + }, + + onended: { + get: function(){ + return this._voltage.onended + }, + set: function(value){ + this._voltage.onended = value; + } + } + + }; + + var flat = new Float32Array([1,1]); + function getVoltage(context){ + var voltage = context.createBufferSource(); + var buffer = context.createBuffer(1, 2, context.sampleRate); + buffer.getChannelData(0).set(flat); + voltage.buffer = buffer; + voltage.loop = true; + return voltage + } + + function scale(node){ + var gain = node.context.createGain(); + node.connect(gain); + return gain + } + + function getTimeConstant(time){ + return Math.log(time+1)/Math.log(100) + } + + function getValue(start, end, fromTime, toTime, at){ + var difference = end - start; + var time = toTime - fromTime; + var truncateTime = at - fromTime; + var phase = truncateTime / time; + var value = start + phase * difference; + + if (value <= start) { + value = start; + } + if (value >= end) { + value = end; + } + + return value + } + + },{}],4:[function(require,module,exports){ + + // DECODE UTILITIES + function b64ToUint6 (nChr) { + return nChr > 64 && nChr < 91 ? nChr - 65 + : nChr > 96 && nChr < 123 ? nChr - 71 + : nChr > 47 && nChr < 58 ? nChr + 4 + : nChr === 43 ? 62 + : nChr === 47 ? 63 + : 0 + } + + // Decode Base64 to Uint8Array + // --------------------------- + function decode (sBase64, nBlocksSize) { + var sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ''); + var nInLen = sB64Enc.length; + var nOutLen = nBlocksSize + ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize + : nInLen * 3 + 1 >> 2; + var taBytes = new Uint8Array(nOutLen); + + for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) { + nMod4 = nInIdx & 3; + nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4; + if (nMod4 === 3 || nInLen - nInIdx === 1) { + for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) { + taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255; + } + nUint24 = 0; + } + } + return taBytes + } + + module.exports = { decode: decode }; + + },{}],5:[function(require,module,exports){ + + /** + * Given a url and a return type, returns a promise to the content of the url + * Basically it wraps a XMLHttpRequest into a Promise + * + * @param {String} url + * @param {String} type - can be 'text' or 'arraybuffer' + * @return {Promise} + */ + module.exports = function (url, type) { + return new Promise(function (done, reject) { + var req = new XMLHttpRequest(); + if (type) req.responseType = type; + + req.open('GET', url); + req.onload = function () { + req.status === 200 ? done(req.response) : reject(Error(req.statusText)); + }; + req.onerror = function () { reject(Error('Network Error')); }; + req.send(); + }) + }; + + },{}],6:[function(require,module,exports){ + + var base64 = require('./base64'); + var fetch = require('./fetch'); + + // Given a regex, return a function that test if against a string + function fromRegex (r) { + return function (o) { return typeof o === 'string' && r.test(o) } + } + // Try to apply a prefix to a name + function prefix (pre, name) { + return typeof pre === 'string' ? pre + name + : typeof pre === 'function' ? pre(name) + : name + } + + /** + * Load one or more audio files + * + * + * Possible option keys: + * + * - __from__ {Function|String}: a function or string to convert from file names to urls. + * If is a string it will be prefixed to the name: + * `load(ac, 'snare.mp3', { from: 'http://audio.net/samples/' })` + * If it's a function it receives the file name and should return the url as string. + * - __only__ {Array} - when loading objects, if provided, only the given keys + * will be included in the decoded object: + * `load(ac, 'piano.json', { only: ['C2', 'D2'] })` + * + * @param {AudioContext} ac - the audio context + * @param {Object} source - the object to be loaded + * @param {Object} options - (Optional) the load options for that object + * @param {Object} defaultValue - (Optional) the default value to return as + * in a promise if not valid loader found + */ + function load (ac, source, options, defVal) { + var loader = + // Basic audio loading + isArrayBuffer(source) ? loadArrayBuffer + : isAudioFileName(source) ? loadAudioFile + : isPromise(source) ? loadPromise + // Compound objects + : isArray(source) ? loadArrayData + : isObject(source) ? loadObjectData + : isJsonFileName(source) ? loadJsonFile + // Base64 encoded audio + : isBase64Audio(source) ? loadBase64Audio + : isJsFileName(source) ? loadMidiJSFile + : null; + + var opts = options || {}; + return loader ? loader(ac, source, opts) + : defVal ? Promise.resolve(defVal) + : Promise.reject('Source not valid (' + source + ')') + } + load.fetch = fetch; + + // BASIC AUDIO LOADING + // =================== + + // Load (decode) an array buffer + function isArrayBuffer (o) { return o instanceof ArrayBuffer } + function loadArrayBuffer (ac, array, options) { + return new Promise(function (done, reject) { + ac.decodeAudioData(array, + function (buffer) { done(buffer); }, + function () { reject("Can't decode audio data (" + array.slice(0, 30) + '...)'); } + ); + }) + } + + // Load an audio filename + var isAudioFileName = fromRegex(/\.(mp3|wav|ogg)(\?.*)?$/i); + function loadAudioFile (ac, name, options) { + var url = prefix(options.from, name); + return load(ac, load.fetch(url, 'arraybuffer'), options) + } + + // Load the result of a promise + function isPromise (o) { return o && typeof o.then === 'function' } + function loadPromise (ac, promise, options) { + return promise.then(function (value) { + return load(ac, value, options) + }) + } + + // COMPOUND OBJECTS + // ================ + + // Try to load all the items of an array + var isArray = Array.isArray; + function loadArrayData (ac, array, options) { + return Promise.all(array.map(function (data) { + return load(ac, data, options, data) + })) + } + + // Try to load all the values of a key/value object + function isObject (o) { return o && typeof o === 'object' } + function loadObjectData (ac, obj, options) { + var dest = {}; + var promises = Object.keys(obj).map(function (key) { + if (options.only && options.only.indexOf(key) === -1) return null + var value = obj[key]; + return load(ac, value, options, value).then(function (audio) { + dest[key] = audio; + }) + }); + return Promise.all(promises).then(function () { return dest }) + } + + // Load the content of a JSON file + var isJsonFileName = fromRegex(/\.json(\?.*)?$/i); + function loadJsonFile (ac, name, options) { + var url = prefix(options.from, name); + return load(ac, load.fetch(url, 'text').then(JSON.parse), options) + } + + // BASE64 ENCODED FORMATS + // ====================== + + // Load strings with Base64 encoded audio + var isBase64Audio = fromRegex(/^data:audio/); + function loadBase64Audio (ac, source, options) { + var i = source.indexOf(','); + return load(ac, base64.decode(source.slice(i + 1)).buffer, options) + } + + // Load .js files with MidiJS soundfont prerendered audio + var isJsFileName = fromRegex(/\.js(\?.*)?$/i); + function loadMidiJSFile (ac, name, options) { + var url = prefix(options.from, name); + return load(ac, load.fetch(url, 'text').then(midiJsToJson), options) + } + + // convert a MIDI.js javascript soundfont file to json + function midiJsToJson (data) { + var begin = data.indexOf('MIDI.Soundfont.'); + if (begin < 0) throw Error('Invalid MIDI.js Soundfont format') + begin = data.indexOf('=', begin) + 2; + var end = data.lastIndexOf(','); + return JSON.parse(data.slice(begin, end) + '}') + } + + if (typeof module === 'object' && module.exports) module.exports = load; + if (typeof window !== 'undefined') window.loadAudio = load; + + },{"./base64":4,"./fetch":5}],7:[function(require,module,exports){ + (function (global){ + (function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e();}else if(typeof define==="function"&&define.amd){define([],e);}else{var t;if(typeof window!=="undefined"){t=window;}else if(typeof global!=="undefined"){t=global;}else if(typeof self!=="undefined"){t=self;}else{t=this;}t.midimessage=e();}})(function(){return function o(e,t,s){function a(n,i){if(!t[n]){if(!e[n]){var l=typeof require=="function"&&require;if(!i&&l)return l(n,!0);if(r)return r(n,!0);var h=new Error("Cannot find module '"+n+"'");throw h.code="MODULE_NOT_FOUND",h}var c=t[n]={exports:{}};e[n][0].call(c.exports,function(t){var s=e[n][1][t];return a(s?s:t)},c,c.exports,o,e,t,s);}return t[n].exports}var r=typeof require=="function"&&require;for(var n=0;n6?null:C.charAt(t)+f(n)+a(r)}function p(t){if((r(t)||e(t))&&t>=0&&t<128)return +t;var n=i(t);return n&&u(n.midi)?n.midi:null}function s(t,n){var r=p(t);return null===r?null:c(r,n)}function d(t){return (i(t)||{}).letter}function m(t){return (i(t)||{}).acc}function h(t){return (i(t)||{}).pc}function v(t){return (i(t)||{}).step}function g(t){return (i(t)||{}).alt}function x(t){return (i(t)||{}).chroma}function y(t){return (i(t)||{}).oct}var b=/^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)\s*$/,A=[0,2,4,5,7,9,11],C="CDEFGAB";t.regex=o,t.parse=i,t.build=l,t.midi=p,t.freq=s,t.letter=d,t.acc=m,t.pc=h,t.step=v,t.alt=g,t.chroma=x,t.oct=y;}); + + + },{}],9:[function(require,module,exports){ + + module.exports = function (player) { + /** + * Adds a listener of an event + * @chainable + * @param {String} event - the event name + * @param {Function} callback - the event handler + * @return {SamplePlayer} the player + * @example + * player.on('start', function(time, note) { + * console.log(time, note) + * }) + */ + player.on = function (event, cb) { + if (arguments.length === 1 && typeof event === 'function') return player.on('event', event) + var prop = 'on' + event; + var old = player[prop]; + player[prop] = old ? chain(old, cb) : cb; + return player + }; + return player + }; + + function chain (fn1, fn2) { + return function (a, b, c, d) { fn1(a, b, c, d); fn2(a, b, c, d); } + } + + },{}],10:[function(require,module,exports){ + + var player = require('./player'); + var events = require('./events'); + var notes = require('./notes'); + var scheduler = require('./scheduler'); + var midi = require('./midi'); + + function SamplePlayer (ac, source, options) { + return midi(scheduler(notes(events(player(ac, source, options))))) + } + + if (typeof module === 'object' && module.exports) module.exports = SamplePlayer; + if (typeof window !== 'undefined') window.SamplePlayer = SamplePlayer; + + },{"./events":9,"./midi":11,"./notes":12,"./player":13,"./scheduler":14}],11:[function(require,module,exports){ + var midimessage = require('midimessage'); + + module.exports = function (player) { + /** + * Connect a player to a midi input + * + * The options accepts: + * + * - channel: the channel to listen to. Listen to all channels by default. + * + * @param {MIDIInput} input + * @param {Object} options - (Optional) + * @return {SamplePlayer} the player + * @example + * var piano = player(...) + * window.navigator.requestMIDIAccess().then(function (midiAccess) { + * midiAccess.inputs.forEach(function (midiInput) { + * piano.listenToMidi(midiInput) + * }) + * }) + */ + player.listenToMidi = function (input, options) { + var started = {}; + var opts = options || {}; + var gain = opts.gain || function (vel) { return vel / 127 }; + + input.onmidimessage = function (msg) { + var mm = msg.messageType ? msg : midimessage(msg); + if (mm.messageType === 'noteon' && mm.velocity === 0) { + mm.messageType = 'noteoff'; + } + if (opts.channel && mm.channel !== opts.channel) return + + switch (mm.messageType) { + case 'noteon': + started[mm.key] = player.play(mm.key, 0, { gain: gain(mm.velocity) }); + break + case 'noteoff': + if (started[mm.key]) { + started[mm.key].stop(); + delete started[mm.key]; + } + break + } + }; + return player + }; + return player + }; + + },{"midimessage":7}],12:[function(require,module,exports){ + + var note = require('note-parser'); + var isMidi = function (n) { return n !== null && n !== [] && n >= 0 && n < 129 }; + var toMidi = function (n) { return isMidi(n) ? +n : note.midi(n) }; + + // Adds note name to midi conversion + module.exports = function (player) { + if (player.buffers) { + var map = player.opts.map; + var toKey = typeof map === 'function' ? map : toMidi; + var mapper = function (name) { + return name ? toKey(name) || name : null + }; + + player.buffers = mapBuffers(player.buffers, mapper); + var start = player.start; + player.start = function (name, when, options) { + var key = mapper(name); + var dec = key % 1; + if (dec) { + key = Math.floor(key); + options = Object.assign(options || {}, { cents: Math.floor(dec * 100) }); + } + return start(key, when, options) + }; + } + return player + }; + + function mapBuffers (buffers, toKey) { + return Object.keys(buffers).reduce(function (mapped, name) { + mapped[toKey(name)] = buffers[name]; + return mapped + }, {}) + } + + },{"note-parser":15}],13:[function(require,module,exports){ + + var ADSR = require('adsr'); + + var EMPTY = {}; + var DEFAULTS = { + gain: 1, + attack: 0.01, + decay: 0.1, + sustain: 0.9, + release: 0.3, + loop: false, + cents: 0, + loopStart: 0, + loopEnd: 0 + }; + + /** + * Create a sample player. + * + * @param {AudioContext} ac - the audio context + * @param {ArrayBuffer|Object} source + * @param {Onject} options - (Optional) an options object + * @return {player} the player + * @example + * var SamplePlayer = require('sample-player') + * var ac = new AudioContext() + * var snare = SamplePlayer(ac, ) + * snare.play() + */ + function SamplePlayer (ac, source, options) { + var connected = false; + var nextId = 0; + var tracked = {}; + var out = ac.createGain(); + out.gain.value = 1; + + var opts = Object.assign({}, DEFAULTS, options); + + /** + * @namespace + */ + var player = { context: ac, out: out, opts: opts }; + if (source instanceof AudioBuffer) player.buffer = source; + else player.buffers = source; + + /** + * Start a sample buffer. + * + * The returned object has a function `stop(when)` to stop the sound. + * + * @param {String} name - the name of the buffer. If the source of the + * SamplePlayer is one sample buffer, this parameter is not required + * @param {Float} when - (Optional) when to start (current time if by default) + * @param {Object} options - additional sample playing options + * @return {AudioNode} an audio node with a `stop` function + * @example + * var sample = player(ac, ).connect(ac.destination) + * sample.start() + * sample.start(5, { gain: 0.7 }) // name not required since is only one AudioBuffer + * @example + * var drums = player(ac, { snare: , kick: , ... }).connect(ac.destination) + * drums.start('snare') + * drums.start('snare', 0, { gain: 0.3 }) + */ + player.start = function (name, when, options) { + // if only one buffer, reorder arguments + if (player.buffer && name !== null) return player.start(null, name, when) + + var buffer = name ? player.buffers[name] : player.buffer; + if (!buffer) { + console.warn('Buffer ' + name + ' not found.'); + return + } else if (!connected) { + console.warn('SamplePlayer not connected to any node.'); + return + } + + var opts = options || EMPTY; + when = Math.max(ac.currentTime, when || 0); + player.emit('start', when, name, opts); + var node = createNode(name, buffer, opts); + node.id = track(name, node); + node.env.start(when); + node.source.start(when); + player.emit('started', when, node.id, node); + if (opts.duration) node.stop(when + opts.duration); + return node + }; + + // NOTE: start will be override so we can't copy the function reference + // this is obviously not a good design, so this code will be gone soon. + /** + * An alias for `player.start` + * @see player.start + * @since 0.3.0 + */ + player.play = function (name, when, options) { + return player.start(name, when, options) + }; + + /** + * Stop some or all samples + * + * @param {Float} when - (Optional) an absolute time in seconds (or currentTime + * if not specified) + * @param {Array} nodes - (Optional) an array of nodes or nodes ids to stop + * @return {Array} an array of ids of the stoped samples + * + * @example + * var longSound = player(ac, ).connect(ac.destination) + * longSound.start(ac.currentTime) + * longSound.start(ac.currentTime + 1) + * longSound.start(ac.currentTime + 2) + * longSound.stop(ac.currentTime + 3) // stop the three sounds + */ + player.stop = function (when, ids) { + var node; + ids = ids || Object.keys(tracked); + return ids.map(function (id) { + node = tracked[id]; + if (!node) return null + node.stop(when); + return node.id + }) + }; + /** + * Connect the player to a destination node + * + * @param {AudioNode} destination - the destination node + * @return {AudioPlayer} the player + * @chainable + * @example + * var sample = player(ac, ).connect(ac.destination) + */ + player.connect = function (dest) { + connected = true; + out.connect(dest); + return player + }; + + player.emit = function (event, when, obj, opts) { + if (player.onevent) player.onevent(event, when, obj, opts); + var fn = player['on' + event]; + if (fn) fn(when, obj, opts); + }; + + return player + + // =============== PRIVATE FUNCTIONS ============== // + + function track (name, node) { + node.id = nextId++; + tracked[node.id] = node; + node.source.onended = function () { + var now = ac.currentTime; + node.source.disconnect(); + node.env.disconnect(); + node.disconnect(); + player.emit('ended', now, node.id, node); + }; + return node.id + } + + function createNode (name, buffer, options) { + var node = ac.createGain(); + node.gain.value = 0; // the envelope will control the gain + node.connect(out); + + node.env = envelope(ac, options, opts); + node.env.connect(node.gain); + + node.source = ac.createBufferSource(); + node.source.buffer = buffer; + node.source.connect(node); + node.source.loop = options.loop || opts.loop; + node.source.playbackRate.value = centsToRate(options.cents || opts.cents); + node.source.loopStart = options.loopStart || opts.loopStart; + node.source.loopEnd = options.loopEnd || opts.loopEnd; + node.stop = function (when) { + var time = when || ac.currentTime; + player.emit('stop', time, name); + var stopAt = node.env.stop(time); + node.source.stop(stopAt); + }; + return node + } + } + + function isNum (x) { return typeof x === 'number' } + var PARAMS = ['attack', 'decay', 'sustain', 'release']; + function envelope (ac, options, opts) { + var env = ADSR(ac); + var adsr = options.adsr || opts.adsr; + PARAMS.forEach(function (name, i) { + if (adsr) env[name] = adsr[i]; + else env[name] = options[name] || opts[name]; + }); + env.value.value = isNum(options.gain) ? options.gain + : isNum(opts.gain) ? opts.gain : 1; + return env + } + + /* + * Get playback rate for a given pitch change (in cents) + * Basic [math](http://www.birdsoft.demon.co.uk/music/samplert.htm): + * f2 = f1 * 2^( C / 1200 ) + */ + function centsToRate (cents) { return cents ? Math.pow(2, cents / 1200) : 1 } + + module.exports = SamplePlayer; + + },{"adsr":3}],14:[function(require,module,exports){ + + var isArr = Array.isArray; + var isObj = function (o) { return o && typeof o === 'object' }; + var OPTS = {}; + + module.exports = function (player) { + /** + * Schedule a list of events to be played at specific time. + * + * It supports three formats of events for the events list: + * + * - An array with [time, note] + * - An array with [time, object] + * - An object with { time: ?, [name|note|midi|key]: ? } + * + * @param {Float} time - an absolute time to start (or AudioContext's + * currentTime if provided number is 0) + * @param {Array} events - the events list. + * @return {Array} an array of ids + * + * @example + * // Event format: [time, note] + * var piano = player(ac, ...).connect(ac.destination) + * piano.schedule(0, [ [0, 'C2'], [0.5, 'C3'], [1, 'C4'] ]) + * + * @example + * // Event format: an object { time: ?, name: ? } + * var drums = player(ac, ...).connect(ac.destination) + * drums.schedule(0, [ + * { name: 'kick', time: 0 }, + * { name: 'snare', time: 0.5 }, + * { name: 'kick', time: 1 }, + * { name: 'snare', time: 1.5 } + * ]) + */ + player.schedule = function (time, events) { + var now = player.context.currentTime; + var when = time < now ? now : time; + player.emit('schedule', when, events); + var t, o, note, opts; + return events.map(function (event) { + if (!event) return null + else if (isArr(event)) { + t = event[0]; o = event[1]; + } else { + t = event.time; o = event; + } + + if (isObj(o)) { + note = o.name || o.key || o.note || o.midi || null; + opts = o; + } else { + note = o; + opts = OPTS; + } + + return player.start(note, when + (t || 0), opts) + }) + }; + return player + }; + + },{}],15:[function(require,module,exports){ + + var REGEX = /^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)\s*$/; + /** + * A regex for matching note strings in scientific notation. + * + * @name regex + * @function + * @return {RegExp} the regexp used to parse the note name + * + * The note string should have the form `letter[accidentals][octave][element]` + * where: + * + * - letter: (Required) is a letter from A to G either upper or lower case + * - accidentals: (Optional) can be one or more `b` (flats), `#` (sharps) or `x` (double sharps). + * They can NOT be mixed. + * - octave: (Optional) a positive or negative integer + * - element: (Optional) additionally anything after the duration is considered to + * be the element name (for example: 'C2 dorian') + * + * The executed regex contains (by array index): + * + * - 0: the complete string + * - 1: the note letter + * - 2: the optional accidentals + * - 3: the optional octave + * - 4: the rest of the string (trimmed) + * + * @example + * var parser = require('note-parser') + * parser.regex.exec('c#4') + * // => ['c#4', 'c', '#', '4', ''] + * parser.regex.exec('c#4 major') + * // => ['c#4major', 'c', '#', '4', 'major'] + * parser.regex().exec('CMaj7') + * // => ['CMaj7', 'C', '', '', 'Maj7'] + */ + function regex () { return REGEX } + + var SEMITONES = [0, 2, 4, 5, 7, 9, 11]; + /** + * Parse a note name in scientific notation an return it's components, + * and some numeric properties including midi number and frequency. + * + * @name parse + * @function + * @param {String} note - the note string to be parsed + * @param {Boolean} isTonic - true if the note is the tonic of something. + * If true, en extra tonicOf property is returned. It's false by default. + * @param {Float} tunning - The frequency of A4 note to calculate frequencies. + * By default it 440. + * @return {Object} the parsed note name or null if not a valid note + * + * The parsed note name object will ALWAYS contains: + * - letter: the uppercase letter of the note + * - acc: the accidentals of the note (only sharps or flats) + * - pc: the pitch class (letter + acc) + * - step: s a numeric representation of the letter. It's an integer from 0 to 6 + * where 0 = C, 1 = D ... 6 = B + * - alt: a numeric representation of the accidentals. 0 means no alteration, + * positive numbers are for sharps and negative for flats + * - chroma: a numeric representation of the pitch class. It's like midi for + * pitch classes. 0 = C, 1 = C#, 2 = D ... It can have negative values: -1 = Cb. + * Can detect pitch class enhramonics. + * + * If the note has octave, the parser object will contain: + * - oct: the octave number (as integer) + * - midi: the midi number + * - freq: the frequency (using tuning parameter as base) + * + * If the parameter `isTonic` is set to true, the parsed object will contain: + * - tonicOf: the rest of the string that follows note name (left and right trimmed) + * + * @example + * var parse = require('note-parser').parse + * parse('Cb4') + * // => { letter: 'C', acc: 'b', pc: 'Cb', step: 0, alt: -1, chroma: -1, + * oct: 4, midi: 59, freq: 246.94165062806206 } + * // if no octave, no midi, no freq + * parse('fx') + * // => { letter: 'F', acc: '##', pc: 'F##', step: 3, alt: 2, chroma: 7 }) + */ + function parse (str, isTonic, tuning) { + if (typeof str !== 'string') return null + var m = REGEX.exec(str); + if (!m || !isTonic && m[4]) return null + + var p = { letter: m[1].toUpperCase(), acc: m[2].replace(/x/g, '##') }; + p.pc = p.letter + p.acc; + p.step = (p.letter.charCodeAt(0) + 3) % 7; + p.alt = p.acc[0] === 'b' ? -p.acc.length : p.acc.length; + p.chroma = SEMITONES[p.step] + p.alt; + if (m[3]) { + p.oct = +m[3]; + p.midi = p.chroma + 12 * (p.oct + 1); + p.freq = midiToFreq(p.midi, tuning); + } + if (isTonic) p.tonicOf = m[4]; + return p + } + + /** + * Given a midi number, return its frequency + * @param {Integer} midi - midi note number + * @param {Float} tuning - (Optional) the A4 tuning (440Hz by default) + * @return {Float} frequency in hertzs + */ + function midiToFreq (midi, tuning) { + return Math.pow(2, (midi - 69) / 12) * (tuning || 440) + } + + var parser = { parse: parse, regex: regex, midiToFreq: midiToFreq }; + var FNS = ['letter', 'acc', 'pc', 'step', 'alt', 'chroma', 'oct', 'midi', 'freq']; + FNS.forEach(function (name) { + parser[name] = function (src) { + var p = parse(src); + return p && (typeof p[name] !== 'undefined') ? p[name] : null + }; + }); + + module.exports = parser; + + // extra API docs + /** + * Get midi of a note + * + * @name midi + * @function + * @param {String} note - the note name + * @return {Integer} the midi number of the note or null if not a valid note + * or the note does NOT contains octave + * @example + * var parser = require('note-parser') + * parser.midi('A4') // => 69 + * parser.midi('A') // => null + */ + /** + * Get freq of a note in hertzs (in a well tempered 440Hz A4) + * + * @name freq + * @function + * @param {String} note - the note name + * @return {Float} the freq of the number if hertzs or null if not valid note + * or the note does NOT contains octave + * @example + * var parser = require('note-parser') + * parser.freq('A4') // => 440 + * parser.freq('A') // => null + */ + + },{}]}; + +let modulesByID = {}; +function link(id) { + if(!modulesByID[id]) { + let _module = modulesByID[id] = { exports: {} }; + let _require = function(requiredName) { + let requiredID = moduleDefs[id][1][requiredName]; + return link(requiredID || requiredName); + }; + moduleDefs[id][0].call(_module.exports, _require, _module, _module.exports); + } + return modulesByID[id].exports; +} + +let soundfont = link(1); + +class Player { + /** + * Loads the necessary soundfonts and plays a song in a PlaybackStyle in the + * browser. + * @param {AudioContext=} context If you pass it an AudioContext it'll use + * it. Otherwise it'll make its own. + */ + constructor(context) { + this.style = null; + this.context = context || new AudioContext({ latencyHint: "playback" }); + this.initialized = false; + window.player = this; + } + setStyle(style) { + return __awaiter(this, void 0, void 0, function* () { + this.style = style; + if (!style._initialized) { + yield style.init(); + } + this.initialized = false; + this.soundfonts = new Map(); + let promises = []; + for (let instrument of style.getInstruments()) { + let sfpromise; + if (instrument.startsWith('http://') || instrument.startsWith('https://')) { + // Soundfont has a bug where you can't just pass it a URL + // @TODO: open an issue there + sfpromise = soundfont.instrument(this.context, instrument, { + isSoundfontUrl: () => true, + nameToUrl: () => instrument + }); + } + else if (instrument == 'percussion') { + sfpromise = soundfont.instrument(this.context, instrument, { soundfont: 'FluidR3_GM' }); + } + else { + sfpromise = soundfont.instrument(this.context, instrument); + } + promises.push(yield sfpromise.then(font => { + this.soundfonts.set(instrument, font); + })); + } + yield Promise.all(promises); + this.initialized = true; + }); + } + play(song) { + if (!this.style) { + throw new Error('No style selected'); + } + if (!this.initialized) { + throw new Error('A style hasn\'t finished loading'); + } + if (this.context.state == 'suspended') { + this.context.resume(); + } + let compiledSong = this.style.compile(song); + let tempoCoef = 0.4; // WHATEVER IDC HOW ANYTHING WORKS + let startTime = this.context.currentTime + 1; + for (let [instrument, notes] of compiledSong) { + let soundfont = this.soundfonts.get(instrument); + for (let note of notes) { + let start = startTime + (tempoCoef * note.time); + let dur = tempoCoef * note.duration - 0.05; + soundfont.play(note.midi, start, { + duration: dur, + gain: note.volume + }); + } + } + } +} + +export { PlaybackStyle, Player }; diff --git a/dist/playback.web.mjs b/dist/playback.web.mjs new file mode 100644 index 0000000..09baa8c --- /dev/null +++ b/dist/playback.web.mjs @@ -0,0 +1,3930 @@ +/** + * playback by Jacob Bloom + * This software is provided as-is, yadda yadda yadda + */ + +import * as _Tonal from 'https://dev.jspm.io/tonal@2.2.2'; +import _Tonal__default, { } from 'https://dev.jspm.io/tonal@2.2.2'; + +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + +function __awaiter(thisArg, _arguments, P, generator) { + 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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +/** + * Load a file. + * + * * Style locator algorithm: + * 1. If the path begins with http:// or https://, look at that URL + * 2. If the path begins with . or / look in the filesystem or at a relative URL + * 3. Otherwise, look in the styles folder in this repo (which will move to its + * own repo eventually). For these built-in styles, the .play file extension + * is not required. + * + * @param {string} path The path to the file to load. + * @return {string} The content of the file. + */ +function load(stylePath) { + return __awaiter(this, void 0, void 0, function* () { + let isHTTP = stylePath.startsWith('http://') || stylePath.startsWith('https://'); + let isRelative = stylePath.startsWith('.') || stylePath.startsWith('/'); + if (typeof process === 'undefined') { + if (isHTTP || isRelative) { + return fetch(stylePath).then(r => r.text()); + } + else { + let modulePath = ''; //String(import.meta.url).replace(/[^\/]+$/, ''); + stylePath = modulePath + '../../styles/' + stylePath; + if (!stylePath.endsWith('.play')) + stylePath += '.play'; + return fetch(stylePath).then(r => r.text()); + } + } + else { + if (isHTTP) { + const http = yield import(stylePath.startsWith('https://') ? 'https' : 'http'); + return new Promise((resolve, reject) => { + http.get(stylePath, res => { + let body = ''; + res.setEncoding('utf8'); + res.on('data', data => body += data); + res.on('end', () => resolve(body)); + res.on('error', reject); + }); + }); + } + if (!isRelative) { + let path = yield import('path'); + try { + stylePath = path.join(__dirname, '../../styles/', stylePath); + } + catch (_a) { } + if (!stylePath.endsWith('.play')) + stylePath += '.play'; + } + let fs = yield import('fs'); + return (new Promise((resolve, reject) => { + fs.readFile(stylePath, 'utf8', (err, data) => { + if (err) { + reject(err); + } + else { + resolve(data); + } + }); + })); + } + }); +} + +var nearley = (function() { + + function Rule(name, symbols, postprocess) { + this.id = ++Rule.highestId; + this.name = name; + this.symbols = symbols; // a list of literal | regex class | nonterminal + this.postprocess = postprocess; + return this; + } + Rule.highestId = 0; + + Rule.prototype.toString = function(withCursorAt) { + function stringifySymbolSequence (e) { + return e.literal ? JSON.stringify(e.literal) : + e.type ? '%' + e.type : e.toString(); + } + var symbolSequence = (typeof withCursorAt === "undefined") + ? this.symbols.map(stringifySymbolSequence).join(' ') + : ( this.symbols.slice(0, withCursorAt).map(stringifySymbolSequence).join(' ') + + " ● " + + this.symbols.slice(withCursorAt).map(stringifySymbolSequence).join(' ') ); + return this.name + " → " + symbolSequence; + }; + + + // a State is a rule at a position from a given starting point in the input stream (reference) + function State(rule, dot, reference, wantedBy) { + this.rule = rule; + this.dot = dot; + this.reference = reference; + this.data = []; + this.wantedBy = wantedBy; + this.isComplete = this.dot === rule.symbols.length; + } + + State.prototype.toString = function() { + return "{" + this.rule.toString(this.dot) + "}, from: " + (this.reference || 0); + }; + + State.prototype.nextState = function(child) { + var state = new State(this.rule, this.dot + 1, this.reference, this.wantedBy); + state.left = this; + state.right = child; + if (state.isComplete) { + state.data = state.build(); + } + return state; + }; + + State.prototype.build = function() { + var children = []; + var node = this; + do { + children.push(node.right.data); + node = node.left; + } while (node.left); + children.reverse(); + return children; + }; + + State.prototype.finish = function() { + if (this.rule.postprocess) { + this.data = this.rule.postprocess(this.data, this.reference, Parser.fail); + } + }; + + + function Column(grammar, index) { + this.grammar = grammar; + this.index = index; + this.states = []; + this.wants = {}; // states indexed by the non-terminal they expect + this.scannable = []; // list of states that expect a token + this.completed = {}; // states that are nullable + } + + + Column.prototype.process = function(nextColumn) { + var states = this.states; + var wants = this.wants; + var completed = this.completed; + + for (var w = 0; w < states.length; w++) { // nb. we push() during iteration + var state = states[w]; + + if (state.isComplete) { + state.finish(); + if (state.data !== Parser.fail) { + // complete + var wantedBy = state.wantedBy; + for (var i = wantedBy.length; i--; ) { // this line is hot + var left = wantedBy[i]; + this.complete(left, state); + } + + // special-case nullables + if (state.reference === this.index) { + // make sure future predictors of this rule get completed. + var exp = state.rule.name; + (this.completed[exp] = this.completed[exp] || []).push(state); + } + } + + } else { + // queue scannable states + var exp = state.rule.symbols[state.dot]; + if (typeof exp !== 'string') { + this.scannable.push(state); + continue; + } + + // predict + if (wants[exp]) { + wants[exp].push(state); + + if (completed.hasOwnProperty(exp)) { + var nulls = completed[exp]; + for (var i = 0; i < nulls.length; i++) { + var right = nulls[i]; + this.complete(state, right); + } + } + } else { + wants[exp] = [state]; + this.predict(exp); + } + } + } + }; + + Column.prototype.predict = function(exp) { + var rules = this.grammar.byName[exp] || []; + + for (var i = 0; i < rules.length; i++) { + var r = rules[i]; + var wantedBy = this.wants[exp]; + var s = new State(r, 0, this.index, wantedBy); + this.states.push(s); + } + }; + + Column.prototype.complete = function(left, right) { + var copy = left.nextState(right); + this.states.push(copy); + }; + + + function Grammar(rules, start) { + this.rules = rules; + this.start = start || this.rules[0].name; + var byName = this.byName = {}; + this.rules.forEach(function(rule) { + if (!byName.hasOwnProperty(rule.name)) { + byName[rule.name] = []; + } + byName[rule.name].push(rule); + }); + } + + // So we can allow passing (rules, start) directly to Parser for backwards compatibility + Grammar.fromCompiled = function(rules, start) { + var lexer = rules.Lexer; + if (rules.ParserStart) { + start = rules.ParserStart; + rules = rules.ParserRules; + } + var rules = rules.map(function (r) { return (new Rule(r.name, r.symbols, r.postprocess)); }); + var g = new Grammar(rules, start); + g.lexer = lexer; // nb. storing lexer on Grammar is iffy, but unavoidable + return g; + }; + + + function StreamLexer() { + this.reset(""); + } + + StreamLexer.prototype.reset = function(data, state) { + this.buffer = data; + this.index = 0; + this.line = state ? state.line : 1; + this.lastLineBreak = state ? -state.col : 0; + }; + + StreamLexer.prototype.next = function() { + if (this.index < this.buffer.length) { + var ch = this.buffer[this.index++]; + if (ch === '\n') { + this.line += 1; + this.lastLineBreak = this.index; + } + return {value: ch}; + } + }; + + StreamLexer.prototype.save = function() { + return { + line: this.line, + col: this.index - this.lastLineBreak, + } + }; + + StreamLexer.prototype.formatError = function(token, message) { + // nb. this gets called after consuming the offending token, + // so the culprit is index-1 + var buffer = this.buffer; + if (typeof buffer === 'string') { + var nextLineBreak = buffer.indexOf('\n', this.index); + if (nextLineBreak === -1) nextLineBreak = buffer.length; + var line = buffer.substring(this.lastLineBreak, nextLineBreak); + var col = this.index - this.lastLineBreak; + message += " at line " + this.line + " col " + col + ":\n\n"; + message += " " + line + "\n"; + message += " " + Array(col).join(" ") + "^"; + return message; + } else { + return message + " at index " + (this.index - 1); + } + }; + + + function Parser(rules, start, options) { + if (rules instanceof Grammar) { + var grammar = rules; + var options = start; + } else { + var grammar = Grammar.fromCompiled(rules, start); + } + this.grammar = grammar; + + // Read options + this.options = { + keepHistory: false, + lexer: grammar.lexer || new StreamLexer, + }; + for (var key in (options || {})) { + this.options[key] = options[key]; + } + + // Setup lexer + this.lexer = this.options.lexer; + this.lexerState = undefined; + + // Setup a table + var column = new Column(grammar, 0); + var table = this.table = [column]; + + // I could be expecting anything. + column.wants[grammar.start] = []; + column.predict(grammar.start); + // TODO what if start rule is nullable? + column.process(); + this.current = 0; // token index + } + + // create a reserved token for indicating a parse fail + Parser.fail = {}; + + Parser.prototype.feed = function(chunk) { + var lexer = this.lexer; + lexer.reset(chunk, this.lexerState); + + var token; + while (token = lexer.next()) { + // We add new states to table[current+1] + var column = this.table[this.current]; + + // GC unused states + if (!this.options.keepHistory) { + delete this.table[this.current - 1]; + } + + var n = this.current + 1; + var nextColumn = new Column(this.grammar, n); + this.table.push(nextColumn); + + // Advance all tokens that expect the symbol + var literal = token.value; + var value = lexer.constructor === StreamLexer ? token.value : token; + var scannable = column.scannable; + for (var w = scannable.length; w--; ) { + var state = scannable[w]; + var expect = state.rule.symbols[state.dot]; + // Try to consume the token + // either regex or literal + if (expect.test ? expect.test(value) : + expect.type ? expect.type === token.type + : expect.literal === literal) { + // Add it + var next = state.nextState({data: value, token: token, isToken: true, reference: n - 1}); + nextColumn.states.push(next); + } + } + + // Next, for each of the rules, we either + // (a) complete it, and try to see if the reference row expected that + // rule + // (b) predict the next nonterminal it expects by adding that + // nonterminal's start state + // To prevent duplication, we also keep track of rules we have already + // added + + nextColumn.process(); + + // If needed, throw an error: + if (nextColumn.states.length === 0) { + // No states at all! This is not good. + var message = this.lexer.formatError(token, "invalid syntax") + "\n"; + message += "Unexpected " + (token.type ? token.type + " token: " : ""); + message += JSON.stringify(token.value !== undefined ? token.value : token) + "\n"; + var err = new Error(message); + err.offset = this.current; + err.token = token; + throw err; + } + + // maybe save lexer state + if (this.options.keepHistory) { + column.lexerState = lexer.save(); + } + + this.current++; + } + if (column) { + this.lexerState = lexer.save(); + } + + // Incrementally keep track of results + this.results = this.finish(); + + // Allow chaining, for whatever it's worth + return this; + }; + + Parser.prototype.save = function() { + var column = this.table[this.current]; + column.lexerState = this.lexerState; + return column; + }; + + Parser.prototype.restore = function(column) { + var index = column.index; + this.current = index; + this.table[index] = column; + this.table.splice(index + 1); + this.lexerState = column.lexerState; + + // Incrementally keep track of results + this.results = this.finish(); + }; + + // nb. deprecated: use save/restore instead! + Parser.prototype.rewind = function(index) { + if (!this.options.keepHistory) { + throw new Error('set option `keepHistory` to enable rewinding') + } + // nb. recall column (table) indicies fall between token indicies. + // col 0 -- token 0 -- col 1 + this.restore(this.table[index]); + }; + + Parser.prototype.finish = function() { + // Return the possible parsings + var considerations = []; + var start = this.grammar.start; + var column = this.table[this.table.length - 1]; + column.states.forEach(function (t) { + if (t.rule.name === start + && t.dot === t.rule.symbols.length + && t.reference === 0 + && t.data !== Parser.fail) { + considerations.push(t); + } + }); + return considerations.map(function(c) {return c.data; }); + }; + + return { + Parser: Parser, + Grammar: Grammar, + Rule: Rule, + }; + +})(); + +var moo = (function() { + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + // polyfill assign(), so we support IE9+ + var assign = typeof Object.assign === 'function' ? Object.assign : + // https://tc39.github.io/ecma262/#sec-object.assign + function(target, sources) { + if (target == null) { + throw new TypeError('Target cannot be null or undefined'); + } + target = Object(target); + + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + if (source == null) continue + + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + return target + }; + + var hasSticky = typeof new RegExp().sticky === 'boolean'; + + /***************************************************************************/ + + function isRegExp(o) { return o && o.constructor === RegExp } + function isObject(o) { return o && typeof o === 'object' && o.constructor !== RegExp && !Array.isArray(o) } + + function reEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + } + function reGroups(s) { + var re = new RegExp('|' + s); + return re.exec('').length - 1 + } + function reCapture(s) { + return '(' + s + ')' + } + function reUnion(regexps) { + var source = regexps.map(function(s) { + return "(?:" + s + ")" + }).join('|'); + return "(?:" + source + ")" + } + + function regexpOrLiteral(obj) { + if (typeof obj === 'string') { + return '(?:' + reEscape(obj) + ')' + + } else if (isRegExp(obj)) { + // TODO: consider /u support + if (obj.ignoreCase) { throw new Error('RegExp /i flag not allowed') } + if (obj.global) { throw new Error('RegExp /g flag is implied') } + if (obj.sticky) { throw new Error('RegExp /y flag is implied') } + if (obj.multiline) { throw new Error('RegExp /m flag is implied') } + return obj.source + + } else { + throw new Error('not a pattern: ' + obj) + } + } + + function objectToRules(object) { + var keys = Object.getOwnPropertyNames(object); + var result = []; + for (var i=0; i 0) { + throw new Error("RegExp has capture groups: " + regexp + "\nUse (?: … ) instead") + } + if (!hasStates && (options.pop || options.push || options.next)) { + throw new Error("State-switching options are not allowed in stateless lexers (for token '" + options.tokenType + "')") + } + + // try and detect rules matching newlines + if (!options.lineBreaks && regexp.test('\n')) { + throw new Error('Rule should declare lineBreaks: ' + regexp) + } + + // store regex + parts.push(reCapture(pat)); + } + + var suffix = hasSticky ? '' : '|(?:)'; + var flags = hasSticky ? 'ym' : 'gm'; + var combined = new RegExp(reUnion(parts) + suffix, flags); + + return {regexp: combined, groups: groups, error: errorRule} + } + + function compile(rules) { + var result = compileRules(rules); + return new Lexer({start: result}, 'start') + } + + function compileStates(states, start) { + var keys = Object.getOwnPropertyNames(states); + if (!start) start = keys[0]; + + var map = Object.create(null); + for (var i=0; i', pop: true }, + beat_operators: ['|', '+', '-', '*', '/'] + } +}); + +let Nil = Symbol('Nil'); +let cast_bool = function (arg) { + if (arg === Nil || arg === false) { + return false; + } + else { + return true; + } +}; + +// does this have to be an Error? idc +class PlaybackError extends Error { + constructor(message, scope) { + super(`${message}\nScope: "${scope.name}"`); + } +} +/* Import-related errors */ +class ImportError extends PlaybackError { + constructor(message, scope) { + super(message, scope); + } +} +class NoSuchStyleError extends ImportError { + constructor(identifier, scope) { + super(`No style with the name "${identifier}" was imported`, scope); + } +} +class NoSuchTrackError extends ImportError { + constructor(style, track, scope) { + super(`No track with the name "${track}" exists in the style "${style}"`, scope); + } +} +class NoSuchPatternError extends ImportError { + constructor(style, track, pattern, scope) { + super(`Pattern "${style}.${track}.${pattern}" does not exist`, scope); + } +} +/* Function-related errors */ +class FunctionNameError extends PlaybackError { + constructor(identifier, scope) { + super(`No function exists with name "${identifier}"`, scope); + } +} +class FunctionScopeError extends PlaybackError { + constructor(message, scope) { + super(message, scope); + } +} +class FunctionArgumentsError extends PlaybackError { + constructor(message, scope) { + super(message, scope); + } +} +/* Pattern-related errors */ +class TooManyBeatsError extends PlaybackError { + constructor(scope) { + super('Pattern may only contain 1 BeatGroup. Try the join operator "&"', scope); + } +} +/* Beat-related errors*/ +class MelodicBeatInDrumBeatGroupError extends PlaybackError { + constructor(scope) { + super('Unexpected Melodic Beat in a Drum Beat Group', scope); + } +} +class DrumBeatInMelodicBeatGroupError extends PlaybackError { + constructor(scope) { + super('Unexpected Drum Beat in a Melodic Beat Group', scope); + } +} + +/* + * In Playback styles, basically any pair of curly brackets defines a scope + * which inherits settings from its parent scope but can overwrite them. + */ +class Scope { + constructor() { + this.defaultVars = new Map(); + this.vars = new Map(); + this.name = null; + this.type = null; + this.scope = null; + } + inherit() { + this.vars = new Map([...this.defaultVars, ...this.scope.vars]); + } + init(scope) { + this.scope = scope; + // in case this.vars was set in the constructor + this.vars = new Map([...this.defaultVars, ...this.scope.vars, ...this.vars]); + } +} + +class MetaStatement extends Scope { + constructor(functionCalls) { + super(); + this.name = '@meta'; + this.type = '@meta'; + this.functionCalls = functionCalls; + } + init(scope) { + this.scope = scope; + // nothing in here can be dynamic so resolve these at compile time + for (let functionCall of this.functionCalls) { + functionCall.init(this); + functionCall.execute(); + } + scope.metadata = this.vars; + } +} +class OptionsStatement extends Scope { + constructor(functionCalls) { + super(); + this.name = '@options'; + this.type = '@options'; + this.functionCalls = functionCalls; + } + init(scope) { + // nothing in here /should/ be dynamic so resolve these at compile time + for (let functionCall of this.functionCalls) { + functionCall.init(this); + functionCall.execute(); + } + this.scope = scope; + // in this case we're actually overwriting our scope's variables, not + // vise-versa + scope.vars = new Map([...scope.vars, ...this.vars]); + } +} +class ImportStatement { + constructor(path, identifier) { + this.path = path; + this.identifier = identifier; + } +} + +var drumJson = { + "26": "Silence", + "27": "High-Q", + "28": "Slap", + "29": "Scratch Push", + "30": "Scratch Pull", + "31": "Sticks", + "32": "Square Click", + "33": "Metronome Click", + "34": "Metronome Bell", + "35": "Acoustic Bass Drum", + "36": "Bass Drum", + "37": "Side Stick", + "38": "Acoustic Snare", + "39": "Hand Clap", + "40": "Electric Snare", + "41": "Low Floor Tom", + "42": "Closed Hi Hat", + "43": "High Floor Tom", + "44": "Pedal Hi-Hat", + "45": "Low Tom", + "46": "Open Hi-Hat", + "47": "Low-Mid Tom", + "48": "Hi-Mid Tom", + "49": "Crash Cymbal 1", + "50": "High Tom", + "51": "Ride Cymbal 1", + "52": "Chinese Cymbal", + "53": "Ride Bell", + "54": "Tambourine", + "55": "Splash Cymbal", + "56": "Cowbell", + "57": "Crash Cymbal 2", + "58": "Vibraslap", + "59": "Ride Cymbal 2", + "60": "Hi Bongo", + "61": "Low Bongo", + "62": "Mute Hi Conga", + "63": "Open Hi Conga", + "64": "Low Conga", + "65": "High Timbale", + "66": "Low Timbale", + "67": "High Agogo", + "68": "Low Agogo", + "69": "Cabasa", + "70": "Maracas", + "71": "Short Whistle", + "72": "Long Whistle", + "73": "Short Guiro", + "74": "Long Guiro", + "75": "Claves", + "76": "Hi Wood Block", + "77": "Low Wood Block", + "78": "Mute Cuica", + "79": "Open Cuica", + "80": "Mute Triangle", + "81": "Open Triangle", + "82": "Shaker", + "83": "Jingle Bell", + "84": "Bell Tree", + "85": "Castanets", + "86": "Mute Surdo", + "87": "Open Surdo" +}; + +const tonal = _Tonal__default || _Tonal; +/** + * There are some inconsistencies with the official MIDI drum names, this + * transformation will hopefully ease the pain there. + * Note: What's the more general word for case-folding? Just "normalizing"? Eh + * @param {string} name + * @return {string} + */ +function normalizeDrumName(name) { + return name.toLowerCase().replace(/ |-|_/g, ' '); +} +// make a map of drum names, which is the inverse of the given JSON file +let DRUM_MAP = new Map(); +for (let midi in drumJson) { + let name = normalizeDrumName(drumJson[midi]); + DRUM_MAP.set(name, midi); +} +/** + * Special pitch value meaning the note will be set later by a DrumBeatGroup + */ +let AwaitingDrum = Symbol('AwaitingDrum'); +class Note { + /** + * @param {Object} opts Options object. + * @param {number} opts.time The note's time, in beats. + * @param {string | symbol} opts.pitch A string representing the pitch and octave of the note. e.x. 'A4' + * @param {number} opts.duraion The note's duration, in beats. + * @param {number} opts.volume The note's volume, as a float 0-1 (inclusive). + */ + constructor(opts) { + this.time = opts.time; + this.pitch = opts.pitch; + this.duration = opts.duration; + this.volume = opts.volume; + } + /** + * An integer representing the MIDI pitch value of the note. + * @type {number} + */ + get midi() { + if (this.pitch === AwaitingDrum) { + return null; + } + else { + let drumValue = DRUM_MAP.get(normalizeDrumName(this.pitch)); + if (drumValue) { + return drumValue; + } + else { + return tonal.Note.midi(this.pitch); + } + } + } + /** + * An integer 0-127 that roughly correlates to volume + * @type {number} + */ + get velocity() { + return Math.floor(this.volume * 127); + } +} +class NoteSet extends Array { + constructor(...args) { + super(); + this.push(...args); + } +} + +let tonal$1 = {}; +(function(n){function t(n){"string"!=typeof n&&(n="");var t=T.exec(n);return t?[t[1].toUpperCase(),t[2].replace(/x/g,"##"),t[3],t[4]]:null}function r(n,t){return n=Math.round(n),(!0===t?G:I)[n%12]+(Math.floor(n/12)-1)}function e(n,t){for(var r=[];t--;r[t]=t+n);return r}function m(n,t){for(var r=[];t--;r[t]=n-t);return r}function i(n,t){return null===n||null===t?[]:nan(t)})}function P(n){return o(n).filter(function(n,t,r){return 0===t||n!==r[t-1]})}function M(n){return "string"!=typeof n?An:_n[n]||(_n[n]=xn(n))}function a(n){var t=(n+1)%7;return t<0?7+t:t}function l(n,t){if(1===arguments.length)return function(t){return l(n,t)};var r=Kn(n),e=Qn(t);if(null===r||null===e)return null;var m=1===r.length?[r[0]+e[0]]:[r[0]+e[0],r[1]+e[1]];return mn(Un(m[0],m[1]))}function c(n,t){if(1===arguments.length)return function(t){return c(n,t)};var r=Kn(n);return null===r?null:mn(Un(r[0]+t))}function s(n,t){if(1===arguments.length)return function(t){return s(n,t)};var r=Kn(n),e=Kn(t);return null===e||null===r?null:e[0]-r[0]}function f(n,t){return 1===arguments.length?function(t){return l(t,n)}:l(t,n)}function d(n,t,r){var e=Qn(n),m=Qn(t);if(null===e||null===m)return null;var i=[e[0]+r*m[0],e[1]+r*m[1]];return Dn(Wn(i))}function p(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,1)}function b(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,-1)}function h(n,t){if(1===arguments.length)return function(t){return h(n,t)};var r=Kn(n),e=Kn(t);if(null===r||null===e||r.length!==e.length)return null;var m=1===r.length?[e[0]-r[0],-Math.floor(7*(e[0]-r[0])/12)]:[e[0]-r[0],e[1]-r[1]];return Dn(Wn(m))}function v(n,t){if(1===arguments.length)return function(t){return v(n,t)};var r=L(n),e=L(t);return null!==r.midi&&null!==e.midi?e.midi-r.midi:null!==r.chroma&&null!==e.chroma?(e.chroma-r.chroma+12)%12:null}function A(n){if(y(n))return n;if(!Array.isArray(n))return "";var t=[0,0,0,0,0,0,0,0,0,0,0,0];return n.map(nt).forEach(function(n){t[n]=1;}),t.join("")}function g(n){return et=et||i(2048,4095).map(function(n){return n.toString(2)}),"number"==typeof n?et.filter(function(t){return rt(t)===n}):et.slice()}function j(n,t){t=!1!==t;var r=A(n).split("");return Mn(r.map(function(n,e){var m=u(e,r);return t&&"0"===m[0]?null:m.join("")}))}function y(n){return mt.test(n)}function O(n){return y(n)?Mn(n.split("").map(function(n,t){return "1"===n?it[t]:null})):[]}function x(n,t){return 1===arguments.length?function(t){return x(n,t)}:A(n)===A(t)}function _(n,t){return arguments.length>1?_(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t&n)===t})}function z(n,t){return arguments.length>1?z(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t|n)===t})}function q(n,t){return arguments.length>1?q(n)(t):(n=A(n),function(t){return "1"===n[nt(t)]})}function k(n,t){return 1===arguments.length?function(t){return k(n,t)}:t.filter(q(n))}function S(n,t){var r=D(n);return t=t||r[1],pt(t).map(l(r[0]))}function w(n){var t=D(n);return void 0!==Mt(t[1])}function D(n){if("string"!=typeof n)return ["",""];var t=n.indexOf(" "),r=R(n.substring(0,t))||R(n)||"",e=""!==r?n.substring(r.length+1):n;return [r,e.length?e:""]}function E(n,t){var r=C(n);return t=t||r[1],xt(t).intervals.map(l(r[0]))}function C(n){var r=t(n);return ""===r[0]?["",n]:"A"===r[0]&&"ug"===r[3]?["","aug"]:St.test(r[2])?[r[0]+r[1],r[2]+r[3]]:[r[0]+r[1]+r[2],r[3]]}var $="C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B".split(" "),F=function(n){return "string"!=typeof n?$.slice():$.filter(function(t){var r=t[1]||" ";return -1!==n.indexOf(r)})},G=F(" #"),I=F(" b"),T=/^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)$/,B=Object.freeze({pc:null,name:null,step:null,alt:null,oct:null,octStr:null,chroma:null,midi:null,freq:null}),N=[0,2,4,5,7,9,11],L=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var r=t(n);if(""===r[0]||""!==r[3])return B;var e=r[0],m=r[1],i=r[2],u={letter:e,acc:m,octStr:i};return u.pc=u.letter+u.acc,u.name=u.pc+i,u.step=(u.letter.charCodeAt(0)+3)%7,u.alt="b"===u.acc[0]?-u.acc.length:u.acc.length,u.oct=i.length?+i:null,u.chroma=(N[u.step]+u.alt+120)%12,u.midi=null!==u.oct?N[u.step]+u.alt+12*(u.oct+1):null,u.freq=J(u.midi),Object.freeze(u)}),R=function(n){return L(n).name},U=function(n){return L(n).pc},H=function(n){return L(n).midi||+n||null},J=function(n,t){return void 0===t&&(t=440),"number"==typeof n?Math.pow(2,(n-69)/12)*t:null},K=function(n){return L(n).freq||J(n)},Q=Math.log(2),V=Math.log(440),W=function(n){var t=12*(Math.log(n)-V)/Q+69;return Math.round(100*t)/100},X=function(n){return L(n).chroma},Y=function(n){return L(n).oct},Z=function(n){return "CDEFGAB"[n]},nn=function(n,t){return Array(t+1).join(n)},tn=function(n,t){return "number"!=typeof n?"":t(n)},rn=function(n){return tn(n,function(n){return n<0?nn("b",-n):nn("#",n)})},en=function(n,t){void 0===n&&(n={}),void 0===t&&(t=null);var r=t?Object.assign({},L(t),n):n,e=r.step,m=r.alt,i=r.oct,u=Z(e);if(!u)return null;var o=u+rn(m);return i||0===i?o+i:o},mn=en,un=function(n,t){var e=L(n),m=e.alt,i=e.chroma,u=e.midi;if(null===i)return null;var o=!1===t?m<0:m>0;return null===u?U(r(i,o)):r(u,o)},on=function(n){return un(n,!1)},Pn=Object.freeze({names:F,tokenize:t,props:L,name:R,pc:U,midi:H,midiToFreq:J,freq:K,freqToMidi:W,chroma:X,oct:Y,stepToLetter:Z,altToAcc:rn,from:en,build:mn,fromMidi:r,simplify:un,enharmonic:on}),Mn=function(n){return n.filter(function(n){return 0===n||n})},an=function(n){var t=H(n);return null!==t?t:H(n+"-100")},ln=function(n,t){void 0===t&&(t=Math.random);for(var r,e,m=n.length;m;)r=t()*m--|0,e=n[m],n[m]=n[r],n[r]=e;return n},cn=function(n){return 0===n.length?[[]]:cn(n.slice(1)).reduce(function(t,r){return t.concat(n.map(function(t,e){var m=r.slice();return m.splice(e,0,n[0]),m}))},[])},sn=Object.freeze({range:i,rotate:u,compact:Mn,sort:o,unique:P,shuffle:ln,permutations:cn}),fn=new RegExp("^([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})|(AA|A|P|M|m|d|dd)([-+]?\\d+)$"),dn=[0,2,4,5,7,9,11],pn=[0,1,2,3,4,5,6,5,4,3,2,1],bn="1P 2m 2M 3m 3M 4P 5P 6m 6M 7m 7M 8P".split(" "),hn=function(n){return "string"!=typeof n?bn.slice():bn.filter(function(t){return -1!==n.indexOf(t[1])})},vn=function(n){var t=fn.exec(n);return null===t?null:t[1]?[t[1],t[2]]:[t[4],t[3]]},An=Object.freeze({name:null,num:null,q:null,step:null,alt:null,dir:null,type:null,simple:null,semitones:null,chroma:null}),gn=function(n,t){return Array(Math.abs(t)+1).join(n)},jn=function(n,t){return "M"===t&&"M"===n?0:"P"===t&&"P"===n?0:"m"===t&&"M"===n?-1:/^A+$/.test(t)?t.length:/^d+$/.test(t)?"P"===n?-t.length:-t.length-1:null},yn=function(n,t){return 0===t?"M"===n?"M":"P":-1===t&&"M"===n?"m":t>0?gn("A",t):t<0?gn("d","P"===n?t:t+1):null},On=function(n){return (Math.abs(n)-1)%7},xn=function(n){var t=vn(n);if(null===t)return An;var r={num:+t[0],q:t[1]};return r.step=On(r.num),r.type="PMMPPMM"[r.step],"M"===r.type&&"P"===r.q?An:(r.name=""+r.num+r.q,r.dir=r.num<0?-1:1,r.simple=8===r.num||-8===r.num?r.num:r.dir*(r.step+1),r.alt=jn(r.type,r.q),r.oct=Math.floor((Math.abs(r.num)-1)/7),r.semitones=r.dir*(dn[r.step]+r.alt+12*r.oct),r.chroma=(r.dir*(dn[r.step]+r.alt)%12+12)%12,Object.freeze(r))},_n={},zn=function(n){return M(n).num},qn=function(n){return M(n).name},kn=function(n){return M(n).semitones},Sn=function(n){return M(n).chroma},wn=function(n){return "string"==typeof n&&(n=M(n).chroma),"number"==typeof n?pn[n%12]:null},Dn=function(n){void 0===n&&(n={});var t=n.num,r=n.step,e=n.alt,m=n.oct;void 0===m&&(m=1);var i=n.dir;if(void 0!==r&&(t=r+1+7*m),void 0===t)return null;var u=i<0?"-":"",o="PMMPPMM"[On(t)];return u+t+yn(o,e)},En=function(n){var t=M(n);return t===An?null:t.simple+t.q},Cn=function(n){var t=M(n);if(t===An)return null;var r=(7-t.step)%7,e="P"===t.type?-t.alt:-(t.alt+1);return Dn({step:r,alt:e,oct:t.oct,dir:t.dir})},$n=[1,2,2,3,3,4,5,5,6,6,7,7],Fn="P m M m M P d P m M m M".split(" "),Gn=function(n){var t=n<0?-1:1,r=Math.abs(n),e=r%12,m=Math.floor(r/12);return t*($n[e]+7*m)+Fn[e]},In=Object.freeze({names:hn,tokenize:vn,props:M,num:zn,name:qn,semitones:kn,chroma:Sn,ic:wn,build:Dn,simplify:En,invert:Cn,fromSemitones:Gn}),Tn=[0,2,4,-1,1,3,5],Bn=function(n){return Math.floor(7*n/12)},Nn=Tn.map(Bn),Ln=function(n){var t=n.step,r=n.alt,e=n.oct,m=n.dir;void 0===m&&(m=1);var i=Tn[t]+7*r;return null===e?[m*i]:[m*i,m*(e-Nn[t]-4*r)]},Rn=[3,0,4,1,5,2,6],Un=function(n,t,r){var e=Rn[a(n)],m=Math.floor((n+1)/7);return void 0===t?{step:e,alt:m,dir:r}:{step:e,alt:m,oct:t+4*m+Nn[e],dir:r}},Hn=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}},Jn=function(n){return Hn(function(t){var r=n(t);return null===r.name?null:Ln(r)})},Kn=Jn(L),Qn=Jn(M),Vn=function(n){return 7*n[0]+12*n[1]<0},Wn=function(n){return Vn(n)?Un(-n[0],-n[1],-1):Un(n[0],n[1],1)},Xn=Object.freeze({transpose:l,trFifths:c,fifths:s,transposeBy:f,addIntervals:d,add:p,subtract:b,interval:h,semitones:v}),Yn={chromatic:["1P 2m 2M 3m 3M 4P 4A 5P 6m 6M 7m 7M"],lydian:["1P 2M 3M 4A 5P 6M 7M"],major:["1P 2M 3M 4P 5P 6M 7M",["ionian"]],mixolydian:["1P 2M 3M 4P 5P 6M 7m",["dominant"]],dorian:["1P 2M 3m 4P 5P 6M 7m"],aeolian:["1P 2M 3m 4P 5P 6m 7m",["minor"]],phrygian:["1P 2m 3m 4P 5P 6m 7m"],locrian:["1P 2m 3m 4P 5d 6m 7m"],altered:["1P 2m 3m 3M 5d 6m 7m",["super locrian","diminished whole tone","pomeroy"]],iwato:["1P 2m 4P 5d 7m"],hirajoshi:["1P 2M 3m 5P 6m"],kumoijoshi:["1P 2m 4P 5P 6m"],pelog:["1P 2m 3m 5P 6m"],prometheus:["1P 2M 3M 4A 6M 7m"],ritusen:["1P 2M 4P 5P 6M"],scriabin:["1P 2m 3M 5P 6M"],piongio:["1P 2M 4P 5P 6M 7m"],augmented:["1P 2A 3M 5P 5A 7M"],neopolitan:["1P 2m 3m 4P 5P 6m 7M"],diminished:["1P 2M 3m 4P 5d 6m 6M 7M"],egyptian:["1P 2M 4P 5P 7m"],oriental:["1P 2m 3M 4P 5d 6M 7m"],spanish:["1P 2m 3M 4P 5P 6m 7m",["phrygian major"]],flamenco:["1P 2m 3m 3M 4A 5P 7m"],balinese:["1P 2m 3m 4P 5P 6m 7M"],persian:["1P 2m 3M 4P 5d 6m 7M"],bebop:["1P 2M 3M 4P 5P 6M 7m 7M"],enigmatic:["1P 2m 3M 5d 6m 7m 7M"],ichikosucho:["1P 2M 3M 4P 5d 5P 6M 7M"],"melodic minor":["1P 2M 3m 4P 5P 6M 7M"],"melodic minor second mode":["1P 2m 3m 4P 5P 6M 7m"],"lydian augmented":["1P 2M 3M 4A 5A 6M 7M"],"lydian dominant":["1P 2M 3M 4A 5P 6M 7m",["lydian b7"]],"melodic minor fifth mode":["1P 2M 3M 4P 5P 6m 7m",["hindu","mixolydian b6M"]],"locrian #2":["1P 2M 3m 4P 5d 6m 7m"],"locrian major":["1P 2M 3M 4P 5d 6m 7m",["arabian"]],"major pentatonic":["1P 2M 3M 5P 6M",["pentatonic"]],"lydian pentatonic":["1P 3M 4A 5P 7M",["chinese"]],"mixolydian pentatonic":["1P 3M 4P 5P 7m",["indian"]],"locrian pentatonic":["1P 3m 4P 5d 7m",["minor seven flat five pentatonic"]],"minor pentatonic":["1P 3m 4P 5P 7m"],"minor six pentatonic":["1P 3m 4P 5P 6M"],"minor hexatonic":["1P 2M 3m 4P 5P 7M"],"flat three pentatonic":["1P 2M 3m 5P 6M",["kumoi"]],"flat six pentatonic":["1P 2M 3M 5P 6m"],"major flat two pentatonic":["1P 2m 3M 5P 6M"],"whole tone pentatonic":["1P 3M 5d 6m 7m"],"ionian pentatonic":["1P 3M 4P 5P 7M"],"lydian #5P pentatonic":["1P 3M 4A 5A 7M"],"lydian dominant pentatonic":["1P 3M 4A 5P 7m"],"minor #7M pentatonic":["1P 3m 4P 5P 7M"],"super locrian pentatonic":["1P 3m 4d 5d 7m"],"in-sen":["1P 2m 4P 5P 7m"],"vietnamese 1":["1P 3m 4P 5P 6m"],"vietnamese 2":["1P 3m 4P 5P 7m"],"prometheus neopolitan":["1P 2m 3M 4A 6M 7m"],"major blues":["1P 2M 3m 3M 5P 6M"],"minor blues":["1P 3m 4P 5d 5P 7m",["blues"]],"composite blues":["1P 2M 3m 3M 4P 5d 5P 6M 7m"],"augmented heptatonic":["1P 2A 3M 4P 5P 5A 7M"],"dorian #4":["1P 2M 3m 4A 5P 6M 7m"],"lydian diminished":["1P 2M 3m 4A 5P 6M 7M"],"whole tone":["1P 2M 3M 4A 5A 7m"],"leading whole tone":["1P 2M 3M 4A 5A 7m 7M"],"harmonic minor":["1P 2M 3m 4P 5P 6m 7M"],"lydian minor":["1P 2M 3M 4A 5P 6m 7m"],"neopolitan minor":["1P 2m 3m 4P 5P 6m 7M"],"neopolitan major":["1P 2m 3m 4P 5P 6M 7M",["dorian b2"]],"neopolitan major pentatonic":["1P 3M 4P 5d 7m"],"romanian minor":["1P 2M 3m 5d 5P 6M 7m"],"double harmonic lydian":["1P 2m 3M 4A 5P 6m 7M"],"harmonic major":["1P 2M 3M 4P 5P 6m 7M"],"double harmonic major":["1P 2m 3M 4P 5P 6m 7M",["gypsy"]],"hungarian minor":["1P 2M 3m 4A 5P 6m 7M"],"hungarian major":["1P 2A 3M 4A 5P 6M 7m"],"spanish heptatonic":["1P 2m 3m 3M 4P 5P 6m 7m"],"todi raga":["1P 2m 3m 4A 5P 6m 7M"],"malkos raga":["1P 3m 4P 6m 7m"],"kafi raga":["1P 3m 3M 4P 5P 6M 7m 7M"],"purvi raga":["1P 2m 3M 4P 4A 5P 6m 7M"],"bebop dominant":["1P 2M 3M 4P 5P 6M 7m 7M"],"bebop minor":["1P 2M 3m 3M 4P 5P 6M 7m"],"bebop major":["1P 2M 3M 4P 5P 5A 6M 7M"],"bebop locrian":["1P 2m 3m 4P 5d 5P 6m 7m"],"minor bebop":["1P 2M 3m 4P 5P 6m 7m 7M"],"mystery #1":["1P 2m 3M 5d 6m 7m"],"minor six diminished":["1P 2M 3m 4P 5P 6m 6M 7M"],"ionian augmented":["1P 2M 3M 4P 5A 6M 7M"],"lydian #9":["1P 2m 3M 4A 5P 6M 7M"],"six tone symmetric":["1P 2m 3M 4P 5A 6M"]},Zn={M:["1P 3M 5P",["Major",""]],M13:["1P 3M 5P 7M 9M 13M",["maj13","Maj13"]],M6:["1P 3M 5P 13M",["6"]],M69:["1P 3M 5P 6M 9M",["69"]],M7add13:["1P 3M 5P 6M 7M 9M"],M7b5:["1P 3M 5d 7M"],M7b6:["1P 3M 6m 7M"],M7b9:["1P 3M 5P 7M 9m"],M7sus4:["1P 4P 5P 7M"],M9:["1P 3M 5P 7M 9M",["maj9","Maj9"]],M9b5:["1P 3M 5d 7M 9M"],M9sus4:["1P 4P 5P 7M 9M"],Madd9:["1P 3M 5P 9M",["2","add9","add2"]],Maj7:["1P 3M 5P 7M",["maj7","M7"]],Mb5:["1P 3M 5d"],Mb6:["1P 3M 13m"],Msus2:["1P 2M 5P",["add9no3","sus2"]],Msus4:["1P 4P 5P",["sus","sus4"]],Maddb9:["1P 3M 5P 9m"],m:["1P 3m 5P"],m11:["1P 3m 5P 7m 9M 11P",["_11"]],m11b5:["1P 3m 7m 12d 2M 4P",["h11","_11b5"]],m13:["1P 3m 5P 7m 9M 11P 13M",["_13"]],m6:["1P 3m 4P 5P 13M",["_6"]],m69:["1P 3m 5P 6M 9M",["_69"]],m7:["1P 3m 5P 7m",["minor7","_","_7"]],m7add11:["1P 3m 5P 7m 11P",["m7add4"]],m7b5:["1P 3m 5d 7m",["half-diminished","h7","_7b5"]],m9:["1P 3m 5P 7m 9M",["_9"]],m9b5:["1P 3m 7m 12d 2M",["h9","-9b5"]],mMaj7:["1P 3m 5P 7M",["mM7","_M7"]],mMaj7b6:["1P 3m 5P 6m 7M",["mM7b6"]],mM9:["1P 3m 5P 7M 9M",["mMaj9","-M9"]],mM9b6:["1P 3m 5P 6m 7M 9M",["mMaj9b6"]],mb6M7:["1P 3m 6m 7M"],mb6b9:["1P 3m 6m 9m"],o:["1P 3m 5d",["mb5","dim"]],o7:["1P 3m 5d 13M",["diminished","m6b5","dim7"]],o7M7:["1P 3m 5d 6M 7M"],oM7:["1P 3m 5d 7M"],sus24:["1P 2M 4P 5P",["sus4add9"]],madd4:["1P 3m 4P 5P"],madd9:["1P 3m 5P 9M"],4:["1P 4P 7m 10m",["quartal"]],5:["1P 5P"],7:["1P 3M 5P 7m",["Dominant","Dom"]],9:["1P 3M 5P 7m 9M",["79"]],11:["1P 5P 7m 9M 11P"],13:["1P 3M 5P 7m 9M 13M",["13_"]],64:["5P 8P 10M"],"M#5":["1P 3M 5A",["augmented","maj#5","Maj#5","+","aug"]],"M#5add9":["1P 3M 5A 9M",["+add9"]],"M13#11":["1P 3M 5P 7M 9M 11A 13M",["maj13#11","Maj13#11","M13+4","M13#4"]],"M6#11":["1P 3M 5P 6M 11A",["M6b5","6#11","6b5"]],"M69#11":["1P 3M 5P 6M 9M 11A"],"M7#11":["1P 3M 5P 7M 11A",["maj7#11","Maj7#11","M7+4","M7#4"]],"M7#5":["1P 3M 5A 7M",["maj7#5","Maj7#5","maj9#5","M7+"]],"M7#5sus4":["1P 4P 5A 7M"],"M7#9#11":["1P 3M 5P 7M 9A 11A"],"M9#11":["1P 3M 5P 7M 9M 11A",["maj9#11","Maj9#11","M9+4","M9#4"]],"M9#5":["1P 3M 5A 7M 9M",["Maj9#5"]],"M9#5sus4":["1P 4P 5A 7M 9M"],"11b9":["1P 5P 7m 9m 11P"],"13#11":["1P 3M 5P 7m 9M 11A 13M",["13+4","13#4"]],"13#9":["1P 3M 5P 7m 9A 13M",["13#9_"]],"13#9#11":["1P 3M 5P 7m 9A 11A 13M"],"13b5":["1P 3M 5d 6M 7m 9M"],"13b9":["1P 3M 5P 7m 9m 13M"],"13b9#11":["1P 3M 5P 7m 9m 11A 13M"],"13no5":["1P 3M 7m 9M 13M"],"13sus4":["1P 4P 5P 7m 9M 13M",["13sus"]],"69#11":["1P 3M 5P 6M 9M 11A"],"7#11":["1P 3M 5P 7m 11A",["7+4","7#4","7#11_","7#4_"]],"7#11b13":["1P 3M 5P 7m 11A 13m",["7b5b13"]],"7#5":["1P 3M 5A 7m",["+7","7aug","aug7"]],"7#5#9":["1P 3M 5A 7m 9A",["7alt","7#5#9_","7#9b13_"]],"7#5b9":["1P 3M 5A 7m 9m"],"7#5b9#11":["1P 3M 5A 7m 9m 11A"],"7#5sus4":["1P 4P 5A 7m"],"7#9":["1P 3M 5P 7m 9A",["7#9_"]],"7#9#11":["1P 3M 5P 7m 9A 11A",["7b5#9"]],"7#9#11b13":["1P 3M 5P 7m 9A 11A 13m"],"7#9b13":["1P 3M 5P 7m 9A 13m"],"7add6":["1P 3M 5P 7m 13M",["67","7add13"]],"7b13":["1P 3M 7m 13m"],"7b5":["1P 3M 5d 7m"],"7b6":["1P 3M 5P 6m 7m"],"7b9":["1P 3M 5P 7m 9m"],"7b9#11":["1P 3M 5P 7m 9m 11A",["7b5b9"]],"7b9#9":["1P 3M 5P 7m 9m 9A"],"7b9b13":["1P 3M 5P 7m 9m 13m"],"7b9b13#11":["1P 3M 5P 7m 9m 11A 13m",["7b9#11b13","7b5b9b13"]],"7no5":["1P 3M 7m"],"7sus4":["1P 4P 5P 7m",["7sus"]],"7sus4b9":["1P 4P 5P 7m 9m",["susb9","7susb9","7b9sus","7b9sus4","phryg"]],"7sus4b9b13":["1P 4P 5P 7m 9m 13m",["7b9b13sus4"]],"9#11":["1P 3M 5P 7m 9M 11A",["9+4","9#4","9#11_","9#4_"]],"9#11b13":["1P 3M 5P 7m 9M 11A 13m",["9b5b13"]],"9#5":["1P 3M 5A 7m 9M",["9+"]],"9#5#11":["1P 3M 5A 7m 9M 11A"],"9b13":["1P 3M 7m 9M 13m"],"9b5":["1P 3M 5d 7m 9M"],"9no5":["1P 3M 7m 9M"],"9sus4":["1P 4P 5P 7m 9M",["9sus"]],"m#5":["1P 3m 5A",["m+","mb6"]],"m11A 5":["1P 3m 6m 7m 9M 11P"],"m7#5":["1P 3m 6m 7m"],"m9#5":["1P 3m 6m 7m 9M"],"+add#9":["1P 3M 5A 9A"]},nt=function(n){return X(n)||Sn(n)||0},tt=function(n){return parseInt(A(n),2)},rt=function(n){return n.replace(/0/g,"").length},et=null,mt=/^[01]{12}$/,it="1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M".split(" "),ut=Object.freeze({chroma:A,chromas:g,modes:j,isChroma:y,intervals:O,isEqual:x,isSubsetOf:_,isSupersetOf:z,includes:q,filter:k}),ot=function(n){var t=Object.keys(n).sort(),r=[],e=[],m=function(n,t,m){r[n]=t,e[m]=e[m]||[],e[m].push(n);};t.forEach(function(t){var r=n[t][0].split(" "),e=n[t][1],i=A(r);m(t,r,i),e&&e.forEach(function(n){return m(n,r,i)});});var i=Object.keys(r).sort(),u=function(n){return r[n]};return u.names=function(n){return "string"==typeof n?(e[n]||[]).slice():(!0===n?i:t).slice()},u},Pt=function(n,t){var r=function(r){return n(r)||t(r)};return r.names=function(r){return n.names(r).concat(t.names(r))},r},Mt=ot(Yn),at=ot(Zn),lt=Pt(Mt,at),ct=Object.freeze({dictionary:ot,combine:Pt,scale:Mt,chord:at,pcset:lt}),st=Object.freeze({name:null,intervals:[],names:[],chroma:null,setnum:null}),ft=function(n,t){return function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=Mt(n);if(!t)return st;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=Mt.names(r.chroma),Object.freeze(r)},{}),dt=Mt.names,pt=function(n){var t=D(n);return ft(t[1]).intervals},bt=function(n){var t=pt(n),r=S(n);return j(t).map(function(n,e){var m=Mt.names(n)[0];if(m)return [r[e]||t[e],m]}).filter(function(n){return n})},ht=function(n){var t=_(pt(n));return at.names().filter(function(n){return t(at(n))})},vt=function(n){var t=Mn(n.map(U));if(!t.length)return t;var r=t[0],e=P(t);return u(e.indexOf(r),e)},At=function(n){if(!pt(n).length)return [];var t=z(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},gt=function(n){var t=_(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},jt=Object.freeze({props:ft,names:dt,intervals:pt,notes:S,exists:w,tokenize:D,modeNames:bt,chords:ht,toScale:vt,supersets:At,subsets:gt}),yt=at.names,Ot=Object.freeze({name:null,names:[],intervals:[],chroma:null,setnum:null}),xt=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=at(n);if(!t)return Ot;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=at.names(r.chroma),r}),_t=function(n){return xt(C(n)[1]).intervals},zt=function(n){return void 0!==at(C(n)[1])},qt=function(n){if(!_t(n).length)return [];var t=z(_t(n));return at.names().filter(function(n){return t(at(n))})},kt=function(n){var t=_(_t(n));return at.names().filter(function(n){return t(at(n))})},St=/^(6|64|7|9|11|13)$/,wt=Object.freeze({names:yt,props:xt,intervals:_t,notes:E,exists:zt,supersets:qt,subsets:kt,tokenize:C}),Dt=l,Et=h,Ct=L,$t=H,Ft=K,Gt=at,It=Mt;n.Array=sn,n.Note=Pn,n.Interval=In,n.Distance=Xn,n.Scale=jt,n.Chord=wt,n.PcSet=ut,n.Dictionary=ct,n.transpose=Dt,n.interval=Et,n.note=Ct,n.midi=$t,n.freq=Ft,n.chord=Gt,n.scale=It,Object.defineProperty(n,"__esModule",{value:!0});})(tonal$1); + +//import {Nil} from './type_utils.js'; +class MelodicBeatLiteral { + constructor(opts) { + this.time = opts.time || { time: 'auto' }; + this.pitch = opts.pitch; + this.octave = opts.octave || 'inherit'; + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + if (this.time.time === 'auto') { + return this.indexInMeasure + 1; + } + else { + return this.time.time; + } + } + /** + * Normalize a chord into a form tonal can handle + * @param {string} [chord=''] + * @return {string} + */ + static normalizeChord(chord = '') { + return chord + .replace(/-/g, '_') // tonal uses _ over - for minor7 + .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? + } + static chordToScaleName(chord) { + let chordType = tonal$1.Chord.tokenize(chord)[1]; + // @TODO: make this more robust + let names = tonal$1.Chord.props(chordType).names; + if (names.includes('dim')) + return 'diminished'; + if (names.includes('aug')) + return 'augmented'; + if (names.includes('Major')) + return 'major'; + if (names.includes('minor')) + return 'minor'; + if (names.includes('minor7')) + return 'dorian'; + if (names.includes('Dominant')) + return 'mixolydian'; + // if none of the above match, do our best to find the closest fit + let closestScale = 'major'; + names.forEach(name => { + if (name.startsWith('dim')) + closestScale = 'diminished'; + if (name.startsWith('aug')) + closestScale = 'augmented'; + if (name.startsWith('M')) + closestScale = 'major'; + if (name.startsWith('m')) + closestScale = 'minor'; + }); + return closestScale; + } + handleInversion(songIterator, pitches) { + let tonicPC = songIterator.song.getTransposedKey(); + let tonicNote = tonal$1.Note.from({ oct: this.getOctave() }, tonicPC); + let tonic = tonal$1.Note.midi(tonicNote); + let outPitches = []; + for (let pitchNote of pitches) { + let pitch = tonal$1.Note.midi(pitchNote); + if (pitch - tonic >= 6) + pitch -= 12; + outPitches.push(tonal$1.Note.fromMidi(pitch)); + } + return outPitches; + } + static getAnchorChord(anchor, songIterator, currentTime) { + let anchorChord; + switch (anchor) { + case 'KEY': { + anchorChord = songIterator.song.getTransposedKey(); + } + case 'NEXT': { + let nextMeasure = songIterator.getRelative(1); + if (nextMeasure) { + anchorChord = nextMeasure.beats[0].chord; + } + else { + anchorChord = songIterator.song.getTransposedKey(); + } + } + case 'STEP': + case 'ARPEGGIATE': + default: { + // crawl backward through this measure to get the last set beat + let lastSetBeat = Math.floor(currentTime); + let iteratorMeasure = songIterator.getRelative(0); + if (!iteratorMeasure) + break; + do { + const beat = iteratorMeasure.beats[lastSetBeat]; + anchorChord = beat && beat.chord; + lastSetBeat--; + } while (!anchorChord); + } + } + return this.normalizeChord(anchorChord); + } + static anchorChordToRoot(anchorChord, degree, octave) { + let anchorTonic = tonal$1.Chord.tokenize(anchorChord)[0]; + let anchorScaleName = this.chordToScaleName(anchorChord); + let scalePCs = tonal$1.Scale.notes(anchorTonic, anchorScaleName); + let rootPC = scalePCs[degree - 1]; + return tonal$1.Note.from({ oct: octave }, rootPC); + } + getAnchorData(songIterator) { + let anchorChord = MelodicBeatLiteral.getAnchorChord(this.pitch.anchor, songIterator, this.getTime()); + let root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, this.pitch.degree, this.getOctave()); + return [anchorChord, root]; + } + getPitches(songIterator) { + let [anchorChord, root] = this.getAnchorData(songIterator); + let pitches; + if (this.pitch.chord) { + // this feels extremely incorrect + // why would anyone need it to work this way + let anchorChordType = tonal$1.Chord.tokenize(anchorChord)[1]; + pitches = tonal$1.Chord.notes(root, anchorChordType); + } + else { + pitches = [root]; + } + if (this.scope.vars.get('invertible')) { + pitches = this.handleInversion(songIterator, pitches); + } + return pitches; + } + /** + * Returns true if the beat is anchored via STEP or ARPEGGIATE + * @returns {boolean} + */ + isDynamic() { + return ['STEP', 'ARPEGGIATE'].includes(this.pitch.anchor); + } + getOctave() { + if (this.octave === 'inherit') { + return this.scope.vars.get('octave'); + } + else { + return this.octave; + } + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + if (this.time.flag === 'STACCATO') { + return Math.min(0.25, duration); + } + else { + return duration; + } + } + getVolume() { + let volume = this.scope.vars.get('volume'); + if (this.time.flag === 'ACCENTED') + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let notes = new NoteSet(); + let time = this.getTime(); // @TODO: this varies with rolling + let pitches = this.getPitches(songIterator); + let duration = this.getDuration(); // @TODO: this varies with rolling + let volume = this.getVolume(); + for (let pitch of pitches) { + notes.push(new Note({ + time: time, + pitch: pitch, + duration: duration, + volume: volume + })); + } + return notes; + } +} +class DrumBeatLiteral { + constructor(opts) { + this.time = opts.time; + this.accented = opts.accented || false; + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + return this.time; + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + return duration; + } + getVolume() { + let volume = this.scope.vars.get('volume'); + if (this.accented) + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let time = this.getTime(); + let duration = this.getDuration(); + let volume = this.getVolume(); + return new NoteSet(new Note({ + time: time, + pitch: AwaitingDrum, + duration: duration, + volume: volume + })); + } +} + +let definitions = new Map(); +/** + * Make an assertion about argument count and types. + * @param {string} identifier The function name. + * @param {Array} args The arguments passed to the function. + * @param {Array.} types Array of the types (typeof) or classes + * (instanceof) to expect. + * @param {Scope} scope The scope, for error logging. + */ +function assertArgTypes(identifier, args, types, scope) { + if (types == '*') + return; + if (args.length != types.length) { + throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, scope); + } + for (let i in args) { + if (types[i] == '*') + continue; + let arg = args[i]; + if (arg instanceof FunctionCall) { + arg = arg.returns; + if (arg == '*') { + continue; // what's the correct functionality here? cry? + } + else if (typeof types[i] == 'string') { + if (arg != types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); + } + } + else { + if (arg != types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); + } + } + } + else { + if (typeof types[i] == 'string') { + if (typeof arg != types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); + } + } + else { + if (!(arg instanceof types[i])) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); + } + } + } + } +} +/** + * Make an assertion about the scope in which the function is called. + * @param {string} identifier The function's name. + * @param {string='no-meta'} goalscope One of 4 string options: + * - 'meta': the function throws if it's called outside a @meta block. + * - 'options': the function throws if it's called outside an @options block. + * - 'no-config': the function throws if it's called inside a @meta or @options + * block, but runs anywhere else that the parser will let you call a function. + * - 'pattern': the function throws if called outside a pattern scope. + * - 'no-meta' (default): the function throws if it's called inside a @meta + * block, but runs anywhere else that the parser will let you call a function. + * @param {Scope} scope The calling scope. + */ +function assertScope(identifier, goalscope = 'no-meta', scope) { + if (goalscope == 'meta') { + if (scope.type != '@meta') { + throw new FunctionScopeError(`Function "${identifier}" must only be called within a @meta block."`, scope); + } + } + else if (goalscope == 'options') { + if (scope.type != '@options') { + throw new FunctionScopeError(`Function "${identifier}" must only be called within an @options block."`, scope); + } + } + else if (goalscope == 'no-config') { + // ensure that config blocks can be resolved at compile time + if (scope.type == '@meta' || scope.type == '@options') { + throw new FunctionScopeError(`Function "${identifier}" must not be called within a @meta or @options block."`, scope); + } + } + else if (goalscope == 'pattern') { + if (scope.type != 'PatternExpressionGroup') { + throw new FunctionScopeError(`Function "${identifier}" must only be called within a @pattern block."`, scope); + } + // @TODO: what about @pattern foo private() -- makes no sense but yea + } + else if (goalscope == 'no-meta') { + if (scope.type == '@meta') { + throw new FunctionScopeError(`Function "${identifier}" must not be called within a @meta block."`, scope); + } + } +} +/** + * Define a function. + * @param {string} identifier The name of the function. + * @param {Object} opts Options passed. See below. + * @param {Array.|string='*'} opts.types If set, throw error + * unless the arguments passed to the function map to these. Can be strings + * (typeof) or classes (instanceof), or the single string '*' to accept + * anything. See assertArgTypes above. + * @param {string='no-meta'} opts.scope Throw error unless the calling + * scope matches. See assertScope above. + * @param {string|Function|Nil='*'} opts.returns The return type. If set to '*' + * it may return anything (for example, choose() returns one of whatever's + * passed to it regardless of type). + * @param {Function} func The function to run. It's passed 3 arguments: + * - args: an array of the arguments passed in the Playback function call. + * - scope: the calling scope. So it can set in scope.vars. + * - argErr: a function. If the function does further testing on its + * arguments and there's an issue, pass this the error message and it throws. + */ +let define$1 = function (identifier, opts, func) { + let definition = { + types: opts.types || '*', + returns: opts.returns || '*', + scope: opts.scope || 'no-meta', + execute: (args, songIterator, scope) => { + let argErr = message => { + throw new FunctionArgumentsError(message, scope); + }; + return func(args, songIterator, scope, argErr); + } + }; + definitions.set(identifier, definition); +}; +/** + * Quickly define a single-argument function that simply sets a var of the same + * name in its parent scope. + * @param {string} identifier The name of the function. + * @param {string|Function} type Throw unless the argument is of this type (see + * assertArgTypes above). + * @param {?string=null} goalscope Throw error unless the calling scope matches. + * See assertScope above. + */ +let defineVar = function (identifier, type, goalscope = null) { + let opts = { + types: [type], + scope: goalscope, + returns: Nil + }; + define$1(identifier, opts, (args, songIterator, scope, argErr) => { + scope.vars.set(identifier, args[0]); + return Nil; + }); +}; +/** + * Quickly define a function that sets a a var of the same name in its parent + * scope. If it has 0 args it sets the var to true, if it has 1 boolean arg + * it sets the var to that. + * @param {string} identifier The name of the function. + * @param {?string=null} goalscope Throw error unless the calling scope matches. + * See assertScope above. + */ +let defineBoolean = function (identifier, goalscope = null) { + let opts = { + types: '*', + scopes: goalscope, + returns: Nil + }; + define$1(identifier, opts, (args, songIterator, scope, argErr) => { + if (args.length) { + assertArgTypes(identifier, args, ['boolean'], scope); + scope.vars.set(identifier, args[0]); + } + else { + scope.vars.set(identifier, true); + } + return Nil; + }); +}; +/*********** ACTUAL FUNCTION DEFINITIONS ***********/ +/*** @meta functions ***/ +defineVar('name', 'string', 'meta'); +defineVar('author', 'string', 'meta'); +defineVar('description', 'string', 'meta'); +defineVar('playback-version', 'number', 'meta'); +/*** @options functions ***/ +define$1('time-signature', { + types: ['number', 'number'], + scope: 'options', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (!Number.isInteger(Math.log2(args[1]))) { + argErr('Argument 2 of "time-signature" must be a power of 2.'); + } + scope.vars.set('time-signature', [args[0], args[1]]); + return Nil; +}); +defineBoolean('swing', 'options'); +/*** anywhere but @meta functions ***/ +define$1('volume', { + types: ['number'], + scope: 'no-meta', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (args[0] < 0 || args[0] > 1) { + argErr('Argument 1 of "volume" must be in range 0-1 (inclusive).'); + } + scope.vars.set('volume', args[0]); + return Nil; +}); +defineBoolean('invertible', 'no-meta'); +define$1('octave', { + types: ['number'], + scope: 'no-meta', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { + argErr('Argument 1 of "octave" must be an integer 0-9.'); + } + scope.vars.set('octave', args[0]); + return Nil; +}); +/*** anywhere but config functions (strictly dynamic functions) ***/ +define$1('choose', { + types: '*', + scope: 'no-config', + returns: '*' +}, (args, songIterator, scope, argErr) => { + let nonNilArgs = args.filter(arg => arg !== Nil); + if (nonNilArgs.length) { + let index = Math.floor(Math.random() * nonNilArgs.length); + return nonNilArgs[index]; + } + else { + return Nil; + } +}); +let anchorOrNumberToChordAndRoot = function (arg, songIterator) { + let anchorChord, root; + if (typeof arg == 'number') { + anchorChord = MelodicBeatLiteral.getAnchorChord(null, songIterator, 1); + root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, arg, 4); + } + else if (arg.anchor) { + anchorChord = MelodicBeatLiteral.getAnchorChord(arg.anchor, songIterator, 1); + root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, 1, 4); + } + return [anchorChord, root]; +}; +define$1('progression', { + types: '*', + scope: 'no-config', + returns: 'boolean' +}, (args, songIterator, scope, argErr) => { + for (let i in args) { + let arg = args[i]; + let [, goal] = anchorOrNumberToChordAndRoot(arg, songIterator); + if (!goal) { + argErr('Arguments of "progression" must be numbers or anchors.'); + } + let actualMeasure = songIterator.getRelative(Number(i)); + if (!actualMeasure) + return false; + let actualChord = MelodicBeatLiteral.normalizeChord(actualMeasure.beats[0].chord); + let actual = MelodicBeatLiteral.anchorChordToRoot(actualChord, 1, 4); + if (actual != goal) + return false; + } + return true; +}); +define$1('in-scale', { + types: '*', + scope: 'no-config', + returns: 'boolean' +}, (args, songIterator, scope, argErr) => { + let [, note] = anchorOrNumberToChordAndRoot(args[0], songIterator); + let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); + if (!note || !goalChord) { + argErr('Arguments of "in-scale" must be numbers or anchors.'); + } + let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); + let goalScale = tonal$1.Scale.notes(goalTonic, goalScaleName); + return goalScale.includes(note); +}); +define$1('beat-defined', { + types: ['number'], + scope: 'no-config', + returns: 'boolean' +}, (args, songIterator, scope, argErr) => { + let measure = songIterator.getRelative(0); + if (!measure) + return false; + return measure.beats[args[0]].chord !== null; +}); +/*** pattern-only functions ***/ +defineBoolean('private', 'pattern'); +defineVar('length', 'number', 'pattern'); +define$1('chance', { + types: ['number'], + scope: 'pattern', + returns: Nil +}, (args, songIterator, scope, argErr) => { + if (args[0] < 0 || args[0] > 1) { + argErr('Argument 1 of "chance" must be in range 0-1 (inclusive).'); + } + scope.vars.set('chance', args[0]); + return Nil; +}); + +/** + * If the value is a FunctionCall, call it and return the returned value. + * Otherwise, return the value itself. + * @private + */ // @TODO: if this is needed elsewhere, put it somewhere useful. +class FunctionCall { + /** + * @constructor + * @param {string} identifier The name of the function. Ideally it should + * match the name of one of the functions in function_data.js + */ + constructor(identifier, args) { + this.identifier = identifier; + this.definition = definitions.get(identifier); + this.args = args; + this.scope = null; + } + init(scope) { + this.scope = scope; + if (!this.definition) { + throw new FunctionNameError(this.identifier, this.scope); + } + this.returns = this.definition.returns; + assertScope(this.identifier, this.definition.scope, this.scope); + this.args.forEach(arg => { + if (arg.init) + arg.init(scope); + }); + assertArgTypes(this.identifier, this.args, this.definition.types, this.scope); + } + link(ASTs, parentStyle, parentTrack) { + this.args.forEach(arg => { + if (arg.link) + arg.link(ASTs, parentStyle, parentTrack); + }); + } + execute(songIterator) { + if (!this.scope) + throw new Error('function not initialized :('); + let evaluatedArgs = this.args.map(arg => { + if (arg.execute) { + return arg.execute(songIterator); + } + else { + return arg; + } + }); + let returnValue = this.definition.execute(evaluatedArgs, songIterator, this.scope); + if (returnValue === undefined) { + throw new Error(`Function "${this.identifier}" can return undefined`); + } + return returnValue; + } +} + +class PatternExpressionGroup extends Scope { + constructor(expressions) { + super(); + this.type = 'PatternExpressionGroup'; + this.name = '@pattern()'; + this.defaultVars.set('private', false); + this.defaultVars.set('chance', 1); + this.expressions = expressions; + this.functionCalls = []; + this.nonFunctionCallExpressions = []; + } + init(scope, patternStatement = null) { + super.init(scope); + this.patternStatement = patternStatement; + if (this.patternStatement) { + this.name = `@pattern(${this.patternStatement})`; + } + this.expressions.forEach(expression => { + if (expression.init) { + expression.init(this); + } + else { + throw ['expression not initialized:', expression]; + } + if (expression instanceof FunctionCall) { + this.functionCalls.push(expression); + } + else { + this.nonFunctionCallExpressions.push(expression); + } + }); + } + link(ASTs, parentStyle, parentTrack) { + this.expressions.forEach(expression => { + expression.link(ASTs, parentStyle, parentTrack); + }); + } + execute(songIterator, callerIsTrack = false) { + this.inherit(); + let beats = Nil; + for (let function_call of this.functionCalls) { + let return_value = function_call.execute(songIterator); + if (return_value instanceof NoteSet) { + if (beats !== Nil) { + throw new TooManyBeatsError(this); + } + beats = return_value; + } + } + if (callerIsTrack && this.vars.get('private') === true) { + return Nil; // if it's private we can give up now + } + for (let expression of this.nonFunctionCallExpressions) { + if (expression.execute) { + expression = expression.execute(songIterator); + } + if (expression instanceof NoteSet) { + if (beats !== Nil) { + throw new TooManyBeatsError(this); + } + beats = expression; + } + } + return beats; + } +} +class PatternStatement extends PatternExpressionGroup { + constructor(opts) { + if (opts.expression instanceof PatternExpressionGroup) { + // unroll the redundant expression group + super(opts.expression.expressions); + } + else { + super([opts.expression]); + } + this.identifier = opts.identifier; + this.condition = (opts.condition !== undefined) ? opts.condition : null; + } + getChance() { + return this.vars.get('chance'); + } + link(ASTs, parentStyle, parentTrack) { + super.link(ASTs, parentStyle, parentTrack); + if (this.condition && this.condition.link) { + this.condition.link(ASTs, parentStyle, parentTrack); + } + } + init(scope) { + super.init(scope); + if (this.condition && this.condition.init) + this.condition.init(this); + } + execute(songIterator, callerIsTrack = false) { + if (this.condition) { + let condition_value; + if (this.condition.execute) { + condition_value = this.condition.execute(songIterator); + } + else { + condition_value = this.condition; + } + if (cast_bool(condition_value) === false) + return Nil; + } + return super.execute(songIterator, callerIsTrack); + } +} +class PatternCall { + constructor(opts) { + this.import = opts.import || null; + this.track = opts.track || null; + this.pattern = opts.pattern; + this.scope = null; + this.patternStatement = null; + this.prettyprintname = (this.import || 'this') + '.' + + (this.track || 'this') + '.' + + this.pattern; + } + getChance() { + return this.patternStatement.getChance()(); + } + init(scope) { + this.scope = scope; + } + link(ASTs, parentStyle, parentTrack) { + let ast; + if (this.import === null) { + ast = parentStyle; + } + else { + // get path name of style + let importPath = parentStyle.importedStyles.get(this.import); + ast = ASTs.get(importPath); + if (!ast) + throw new NoSuchStyleError(this.import, this); + } + let track; + if (this.track === null) { + track = parentTrack; + } + else { + track = ast.tracks.get(this.track); + if (!track) + throw new NoSuchTrackError(this.import || 'this', this.track || 'this', this); + } + let patternStatement = track.patterns.get(this.pattern); + if (!patternStatement) + throw new NoSuchPatternError(this.import || 'this', this.track || 'this', this.pattern, this); + this.patternStatement = patternStatement; + } + execute(songIterator) { + // called patternStatement ignores private() + return this.patternStatement.execute(songIterator); + } +} +class JoinedPatternExpression { + constructor(patterns) { + this.patterns = patterns; + } + init(scope) { + this.scope = scope; + this.patterns.forEach(pattern => { + if (pattern.init) + pattern.init(scope); + }); + } + link(ASTs, parentStyle, parentTrack) { + this.patterns.forEach(pattern => { + pattern.link(ASTs, parentStyle, parentTrack); + }); + } + execute(songIterator) { + let noteSets = []; + for (let pattern of this.patterns) { + if (pattern.execute) { + pattern = pattern.execute(songIterator); + } + if (pattern instanceof NoteSet) { + noteSets.push(pattern); + } + } + if (noteSets.length) { + return (new NoteSet()).concat(...noteSets); + } + else { + return Nil; + } + } +} + +class TrackStatement extends Scope { + constructor(opts) { + super(); + this.name = opts.identifier; + this.type = '@track'; + this.defaultVars.set('octave', 4); + this.defaultVars.set('volume', 1); + this.defaultVars.set('private', false); + this.instrument = opts.instrument; + this.identifier = opts.identifier; + this.members = opts.members; + } + init(scope) { + super.init(scope); + this.functionCalls = []; + this.patterns = new Map(); + this.patternCalls = []; + this.members.forEach(member => { + // initialize them all now, var inheritence is handled during execution + member.init(this); + if (member instanceof FunctionCall) { + this.functionCalls.push(member); + } + else if (member instanceof PatternStatement) { + this.patterns.set(member.identifier, member); + } + else if (member instanceof PatternCall) { + this.patternCalls.push(member); + } + }); + } + link(ASTs, parentStyle) { + for (let patternCall of this.patternCalls) { + patternCall.link(ASTs, parentStyle, this); + this.patterns.set(patternCall.prettyprintname, patternCall); + } + for (let [, pattern] of this.patterns) { + pattern.link(ASTs, parentStyle, this); + } + } + execute(songIterator) { + this.inherit(); + console.log(`executing TrackStatement "${this.name}"`); + this.functionCalls.forEach(function_call => { + function_call.execute(songIterator); + }); + // weighted random picking + // https://stackoverflow.com/a/4463613/1784306 + // I don't really understand the above explanation, this is probs wrong + let totalWeight = 0; + let weightedOptions = []; + for (let [patternname, pattern] of this.patterns) { + console.log(`- pattern "${patternname}":`); + // true = I'm the instrument so if you're private return Nil + let result = pattern.execute(songIterator, true); + console.log(' - Result:', result); + // @TODO: handle multi-measure patterns (via locks?) + if (result !== Nil) { + for (let note of result) { + if (note.pitch === AwaitingDrum) { + throw new DrumBeatInMelodicBeatGroupError(pattern); + } + } + let chance = pattern.getChance(); + weightedOptions.push({ + noteSet: result, + lower: totalWeight, + upper: totalWeight + chance + }); + totalWeight += chance; + } + } + // binary search would make sense here if I expected more items + let goal = Math.random() * totalWeight; + for (let option of weightedOptions) { + if (option.lower <= goal && goal <= option.upper) { + console.log(' - Final result:', option.noteSet); + return option.noteSet; + } + } + console.log(' - Final result:', Nil); + return Nil; + } +} +class TrackCall { + constructor(opts) { + this.import = opts.import; + this.track = opts.track; + this.trackStatement = null; // will be set by the loader. + } + execute(songIterator) { + this.trackStatement.execute(songIterator); + } +} + +class GlobalScope extends Scope { + constructor(statements) { + super(); + this.name = 'global'; + this.type = 'global'; + this.statements = statements; + } + init() { + // set some default values + this.vars.set('time-signature', [4, 4]); + this.vars.set('tempo', 120); + this.tracks = new Map(); + this.metaStatements = []; + // @TODO: stop circular dependencies? cache them and mark one as mom + this.importedStyles = new Map(); + this.trackCalls = []; + this.dependencies = []; + for (let statement of this.statements) { + if (statement instanceof MetaStatement + || statement instanceof OptionsStatement) { + // @TODO: make sure there's exactly 1 meta block + this.metaStatements.push(statement); + } + else if (statement instanceof ImportStatement) { + this.importedStyles.set(statement.identifier, statement.path); + this.dependencies.push(statement.path); + } + else if (statement instanceof TrackStatement) { + this.tracks.set(statement.name, statement); + } + else if (statement instanceof TrackCall) { + this.trackCalls.push(statement); + } + } + // handle meta blocks first since they set variables in own scope + this.metaStatements.forEach(statement => statement.init(this)); + // -- handle importing before statements -- + this.tracks.forEach(statement => statement.init(this)); + } + link(ASTs) { + for (let trackCall of this.trackCalls) { + // get path name of style + let importPath = this.importedStyles.get(trackCall.import); + let ast = ASTs.get(importPath); + if (!ast) + throw new NoSuchStyleError(trackCall.import, this); + let trackStatement = ast.tracks.get(trackCall.track); + if (!trackStatement) + throw new NoSuchTrackError(trackCall.import, trackCall.track, this); + //trackCall.trackStatement = trackStatement; + this.tracks.set(`${trackCall.import}.${trackCall.track}`, trackStatement); + } + for (let [, track] of this.tracks) { + track.link(ASTs, this); + } + } + execute(songIterator) { + let trackNoteMap = new Map(); + for (let [, track] of this.tracks) { + let trackNotes = track.execute(songIterator); + if (trackNotes !== Nil) + trackNoteMap.set(track.instrument, trackNotes); + } + return trackNoteMap; + } + getInstruments() { + let instruments = new Set(); + for (let [, track] of this.tracks) { + instruments.add(track.instrument); + } + return instruments; + } +} + +class AnchorArgument { + constructor(anchor) { + this.anchor = anchor; + } +} +class BooleanOperator { + constructor(...args) { + this.args = args; + } + link(ASTs, parentStyle, parentTrack) { + this.args.forEach(arg => { + if (arg.link) + arg.link(ASTs, parentStyle, parentTrack); + }); + } + init(scope) { + this.scope = scope; + this.args.forEach(arg => { + if (arg.init) + arg.init(scope); + }); + } + resolve_args(songIterator) { + return this.args.map(arg => { + if (arg.execute) { + return arg.execute(songIterator); + } + else { + return arg; + } + }); + } +} +class BooleanNot extends BooleanOperator { + constructor(...args) { + super(...args); + } + execute(songIterator) { + let args = this.resolve_args(songIterator); + return !cast_bool(args[0]); + } +} +class BooleanAnd extends BooleanOperator { + constructor(...args) { + super(...args); + } + execute(songIterator) { + // sorry no short-circuiting because this code is prettier + // @TODO: add short-circuiting if this actually makes it too slow + let args = this.resolve_args(songIterator); + return cast_bool(args[0]) && cast_bool(args[1]); + } +} +class BooleanOr extends BooleanOperator { + constructor(...args) { + super(...args); + } + execute(songIterator) { + let args = this.resolve_args(songIterator); + return cast_bool(args[0]) || cast_bool(args[1]); + } +} + +class BeatGroupLiteral { + constructor(measures) { + this.measures = measures; + this.scope = null; + } + init(scope) { + this.scope = scope; + this.measures.forEach((measure, i) => measure.init(scope, this, i)); + } + link() { return; } + execute(songIterator) { + let joinedMeasures = new NoteSet(); + for (let i = 0; i < this.measures.length; i++) { + let offset = i * 4; // @TODO: pull in actual meter somehow + let measureNotes = this.measures[i].execute(songIterator); + if (measureNotes === Nil) + return Nil; // lets a/s abort the beatgroup + for (let measureNote of measureNotes) { + measureNote.time += offset; + joinedMeasures.push(measureNote); + } + } + return joinedMeasures; + } + getNextStaticBeatRoot(measureIndex, beatIndex, songIterator) { + // first, try every subsequent beat in the beatGroup + // (including subsequent measures) + let measure, beat; + while (measure = this.parentBeatGroup.measures[measureIndex++]) { + while (beat = measure.beats[++beatIndex]) { + if (!beat.isDynamic()) { + return beat.getAnchorData(songIterator)[1]; + } + } + beatIndex = -1; + } + // if there are no non-dynamic beats in the rest of the beat-group, return + // the first note of the next measure (@TODO: could be multiple measures + // later if it's a multi-measure beatgroup) + // @TODO: wtf? + const nextMeasure = songIterator.getRelative(1); + return MelodicBeatLiteral.normalizeChord(nextMeasure && nextMeasure.beats[0].chord); + } +} +class Measure { + constructor(beats) { + this.beats = beats; + this.beatsPerMeasure = null; + this.scope = null; + } + calculateDurationAfter(beatIndex) { + let currentBeat = this.beats[beatIndex]; + let currentBeatTime = currentBeat.getTime(); + let nextBeatTime; + if (beatIndex + 1 >= this.beats.length) { + nextBeatTime = this.beatsPerMeasure + 1; + } + else { + let nextBeat = this.beats[beatIndex + 1]; + nextBeatTime = nextBeat.getTime(); + } + return nextBeatTime - currentBeatTime; + } + getNextStaticBeatRoot(beatIndex, songIterator) { + return this.parentBeatGroup.getNextStaticBeatRoot(this.indexInBeatGroup, beatIndex, songIterator); + } + init(scope, parentBeatGroup, indexInBeatGroup) { + this.scope = scope; + this.parentBeatGroup = parentBeatGroup; + this.indexInBeatGroup = indexInBeatGroup; + this.beatsPerMeasure = this.scope.vars.get('time-signature')[0]; + // @TODO does this need more math? + this.beats.forEach((beat, i) => { + beat.init(scope, this, i); + }); + } + execute(songIterator) { + // clear cached notes (used for STEP/ARPEGGIATE interpolation) + for (let beat of this.beats) { + if (beat instanceof MelodicBeatLiteral) + beat.cachedAnchor = null; + } + // each beat returns a NoteSet since it could be a chord or whatever + let joined = new NoteSet(); + for (let beat of this.beats) { + let notes = beat.execute(songIterator); + if (notes === Nil) + return Nil; // lets a and s abort the beatgroup. + joined.push(...notes); + } + return joined; + } +} +class DrumBeatGroupLiteral { + constructor(drum, beatGroup) { + this.drum = drum; + this.beatGroup = beatGroup; // for now there's no diff in functionality... + // @TODO make sure our beats are all drummy + } + init(scope) { + this.scope = scope; + if (this.beatGroup.init) + this.beatGroup.init(scope); + } + link() { return; } // @TODO: I think patterncalls are allowed here? + execute(songIterator) { + let notes = this.beatGroup.execute(songIterator); + for (let note of notes) { + if (note.pitch === AwaitingDrum) { + note.pitch = this.drum; // @TODO: convert to number? + } + else { + throw new MelodicBeatInDrumBeatGroupError(this.scope); + } + } + return notes; + } +} + +// Generated automatically by nearley, version 2.13.0 +// http://github.com/Hardmath123/nearley +function id(x) { return x[0]; } +let Lexer = lexer; +let ParserRules = [ + {"name": "main$macrocall$2", "symbols": ["TopLevelStatement"]}, + {"name": "main$macrocall$1$ebnf$1", "symbols": []}, + {"name": "main$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "main$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "main$macrocall$1$ebnf$1", "symbols": ["main$macrocall$1$ebnf$1", "main$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "main$macrocall$1", "symbols": ["main$macrocall$2", "main$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "main", "symbols": ["_?", "main$macrocall$1", "_?"], "postprocess": d => new GlobalScope(d[1])}, + {"name": "TopLevelStatement", "symbols": ["ConfigurationStatement"], "postprocess": id}, + {"name": "TopLevelStatement", "symbols": ["ImportStatement"], "postprocess": id}, + {"name": "TopLevelStatement", "symbols": ["TrackStatement"], "postprocess": id}, + {"name": "TopLevelStatement", "symbols": ["TrackCallStatement"], "postprocess": id}, + {"name": "ConfigurationStatement", "symbols": [{"literal":"@meta"}, "_?", {"literal":"{"}, "_?", "ConfigurationList", "_?", {"literal":"}"}], "postprocess": d => new MetaStatement(d[4])}, + {"name": "ConfigurationStatement", "symbols": [{"literal":"@options"}, "_?", {"literal":"{"}, "_?", "ConfigurationList", "_?", {"literal":"}"}], "postprocess": d => new OptionsStatement(d[4])}, + {"name": "ConfigurationList$macrocall$2", "symbols": ["FunctionCallExpression"]}, + {"name": "ConfigurationList$macrocall$1$ebnf$1", "symbols": []}, + {"name": "ConfigurationList$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "ConfigurationList$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "ConfigurationList$macrocall$1$ebnf$1", "symbols": ["ConfigurationList$macrocall$1$ebnf$1", "ConfigurationList$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "ConfigurationList$macrocall$1", "symbols": ["ConfigurationList$macrocall$2", "ConfigurationList$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "ConfigurationList", "symbols": ["ConfigurationList$macrocall$1"], "postprocess": id}, + {"name": "ImportStatement", "symbols": [{"literal":"@import"}, "_", "StringLiteral", "_", {"literal":"as"}, "_", "Identifier"], "postprocess": d => new ImportStatement(d[2], d[6])}, + {"name": "TrackStatement$macrocall$2", "symbols": ["TrackMember"]}, + {"name": "TrackStatement$macrocall$1$ebnf$1", "symbols": []}, + {"name": "TrackStatement$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "TrackStatement$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "TrackStatement$macrocall$1$ebnf$1", "symbols": ["TrackStatement$macrocall$1$ebnf$1", "TrackStatement$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "TrackStatement$macrocall$1", "symbols": ["TrackStatement$macrocall$2", "TrackStatement$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "TrackStatement", "symbols": [{"literal":"@track"}, "_", "StringLiteral", "_", {"literal":"as"}, "_", "Identifier", "_?", {"literal":"{"}, "_?", "TrackStatement$macrocall$1", "_?", {"literal":"}"}], "postprocess": d => new TrackStatement({instrument: d[2], identifier: d[6], members: d[10]})}, + {"name": "TrackMember", "symbols": ["FunctionCallExpression"], "postprocess": id}, + {"name": "TrackMember", "symbols": ["PatternStatement"], "postprocess": id}, + {"name": "TrackMember", "symbols": ["PatternCallExpression"], "postprocess": id}, + {"name": "TrackCallStatement", "symbols": [{"literal":"@track"}, "_?", {"literal":"("}, "_?", "Identifier", {"literal":"."}, "Identifier", "_?", {"literal":")"}], "postprocess": d => new TrackCall({import: d[4], track: d[6]})}, + {"name": "PatternStatement", "symbols": [{"literal":"@pattern"}, "_", "Identifier", "_", "PatternConditional", "_?", "PatternExpression"], "postprocess": d => new PatternStatement({identifier: d[2], expression: d[6], condition: d[4]})}, + {"name": "PatternStatement", "symbols": [{"literal":"@pattern"}, "_", "Identifier", "_", "PatternExpression"], "postprocess": d => new PatternStatement({identifier: d[2], expression: d[4]})}, + {"name": "PatternConditional", "symbols": [{"literal":"if"}, "_?", {"literal":"("}, "_?", "FunctionCallArgument", "_?", {"literal":")"}], "postprocess": d => d[4]}, + {"name": "PatternExpression", "symbols": ["PatternExpression_NoJoin"], "postprocess": id}, + {"name": "PatternExpression", "symbols": ["JoinedPatternExpression"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["PatternExpressionGroup"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["BeatGroupLiteral"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["DrumBeatGroupLiteral"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["FunctionCallExpression"], "postprocess": id}, + {"name": "PatternExpression_NoJoin", "symbols": ["PatternCallExpression"], "postprocess": id}, + {"name": "PatternExpressionGroup$macrocall$2", "symbols": ["PatternExpression"]}, + {"name": "PatternExpressionGroup$macrocall$1$ebnf$1", "symbols": []}, + {"name": "PatternExpressionGroup$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "PatternExpressionGroup$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "PatternExpressionGroup$macrocall$1$ebnf$1", "symbols": ["PatternExpressionGroup$macrocall$1$ebnf$1", "PatternExpressionGroup$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "PatternExpressionGroup$macrocall$1", "symbols": ["PatternExpressionGroup$macrocall$2", "PatternExpressionGroup$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "PatternExpressionGroup", "symbols": [{"literal":"{"}, "_?", "PatternExpressionGroup$macrocall$1", "_?", {"literal":"}"}], "postprocess": d => new PatternExpressionGroup(d[2])}, + {"name": "PatternCallExpression", "symbols": [{"literal":"@pattern"}, "_?", {"literal":"("}, "_?", "Identifier", "_?", {"literal":")"}], "postprocess": d => new PatternCall({pattern: d[4]})}, + {"name": "PatternCallExpression", "symbols": [{"literal":"@pattern"}, "_?", {"literal":"("}, "_?", "Identifier", {"literal":"."}, "Identifier", "_?", {"literal":")"}], "postprocess": d => new PatternCall({track: d[4], pattern: d[6]})}, + {"name": "PatternCallExpression", "symbols": [{"literal":"@pattern"}, "_?", {"literal":"("}, "_?", "Identifier", {"literal":"."}, "Identifier", {"literal":"."}, "Identifier", "_?", {"literal":")"}], "postprocess": d => new PatternCall({import: d[4], track: d[6], pattern: d[8]})}, + {"name": "JoinedPatternExpression$macrocall$2", "symbols": ["PatternExpression_NoJoin"]}, + {"name": "JoinedPatternExpression$macrocall$3", "symbols": [{"literal":"&"}]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_?", "JoinedPatternExpression$macrocall$3", "_?", "JoinedPatternExpression$macrocall$2"], "postprocess": d => d[3][0]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1", "symbols": ["JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$1"]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$2", "symbols": ["_?", "JoinedPatternExpression$macrocall$3", "_?", "JoinedPatternExpression$macrocall$2"], "postprocess": d => d[3][0]}, + {"name": "JoinedPatternExpression$macrocall$1$ebnf$1", "symbols": ["JoinedPatternExpression$macrocall$1$ebnf$1", "JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "JoinedPatternExpression$macrocall$1", "symbols": ["JoinedPatternExpression$macrocall$2", "JoinedPatternExpression$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "JoinedPatternExpression", "symbols": ["JoinedPatternExpression$macrocall$1"], "postprocess": d => new JoinedPatternExpression(d[0])}, + {"name": "FunctionCallExpression$macrocall$2", "symbols": ["FunctionCallArgument"]}, + {"name": "FunctionCallExpression$macrocall$1$ebnf$1", "symbols": []}, + {"name": "FunctionCallExpression$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "FunctionCallExpression$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "FunctionCallExpression$macrocall$1$ebnf$1", "symbols": ["FunctionCallExpression$macrocall$1$ebnf$1", "FunctionCallExpression$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "FunctionCallExpression$macrocall$1", "symbols": ["FunctionCallExpression$macrocall$2", "FunctionCallExpression$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, "_?", "FunctionCallExpression$macrocall$1", "_?", {"literal":")"}], "postprocess": d => new FunctionCall(d[0], d[4])}, + {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, {"literal":")"}], "postprocess": d => new FunctionCall(d[0], [])}, + {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["PatternExpression"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new AnchorArgument(d[0])}, + {"name": "FunctionCallArgument", "symbols": [{"literal":"not"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanNot(d[2])}, + {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"and"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanAnd(d[0], d[4])}, + {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"or"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanOr(d[0], d[4])}, + {"name": "BeatGroupLiteral", "symbols": [{"literal":"<"}, "_?", "MeasureGroup", "_?", {"literal":">"}], "postprocess": d => new BeatGroupLiteral(d[2])}, + {"name": "MeasureGroup$macrocall$2", "symbols": ["Measure"]}, + {"name": "MeasureGroup$macrocall$3", "symbols": [{"literal":"|"}]}, + {"name": "MeasureGroup$macrocall$1$ebnf$1", "symbols": []}, + {"name": "MeasureGroup$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_?", "MeasureGroup$macrocall$3", "_?", "MeasureGroup$macrocall$2"], "postprocess": d => d[3][0]}, + {"name": "MeasureGroup$macrocall$1$ebnf$1", "symbols": ["MeasureGroup$macrocall$1$ebnf$1", "MeasureGroup$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "MeasureGroup$macrocall$1", "symbols": ["MeasureGroup$macrocall$2", "MeasureGroup$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "MeasureGroup", "symbols": ["MeasureGroup$macrocall$1"], "postprocess": id}, + {"name": "Measure$macrocall$2", "symbols": ["MelodicBeatLiteral"]}, + {"name": "Measure$macrocall$1$ebnf$1", "symbols": []}, + {"name": "Measure$macrocall$1$ebnf$1$subexpression$1", "symbols": ["_", "Measure$macrocall$2"], "postprocess": d => d[1][0]}, + {"name": "Measure$macrocall$1$ebnf$1", "symbols": ["Measure$macrocall$1$ebnf$1", "Measure$macrocall$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "Measure$macrocall$1", "symbols": ["Measure$macrocall$2", "Measure$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, + {"name": "Measure", "symbols": ["Measure$macrocall$1"], "postprocess": d => new Measure(d[0])}, + {"name": "MelodicBeatLiteral", "symbols": ["BL_TimePart", {"literal":":"}, "BL_PitchPart", {"literal":":"}, "BL_OctavePart"], "postprocess": d => new MelodicBeatLiteral({time: d[0], pitch: d[2], octave: d[4]})}, + {"name": "MelodicBeatLiteral", "symbols": [{"literal":":"}, "BL_PitchPart", {"literal":":"}, "BL_OctavePart"], "postprocess": d => new MelodicBeatLiteral({pitch: d[1], octave: d[3]})}, + {"name": "MelodicBeatLiteral", "symbols": ["BL_TimePart", {"literal":":"}, "BL_PitchPart"], "postprocess": d => new MelodicBeatLiteral({time: d[0], pitch: d[2]})}, + {"name": "MelodicBeatLiteral", "symbols": [{"literal":":"}, "BL_PitchPart"], "postprocess": d => new MelodicBeatLiteral({pitch: d[1]})}, + {"name": "MelodicBeatLiteral", "symbols": ["DrumBeatLiteral"], "postprocess": id}, + {"name": "BL_TimePart", "symbols": ["NumericExpression"], "postprocess": d => ({time: d[0]})}, + {"name": "BL_TimePart", "symbols": ["BL_TP_Flag"], "postprocess": d => ({time: 'auto', flag: d[0]})}, + {"name": "BL_TimePart", "symbols": ["NumericExpression", "BL_TP_Flag"], "postprocess": d => ({time: d[0], flag: d[1]})}, + {"name": "BL_TP_Flag", "symbols": [{"literal":"s"}], "postprocess": d => 'STACCATO'}, + {"name": "BL_TP_Flag", "symbols": [{"literal":"a"}], "postprocess": d => 'ACCENTED'}, + {"name": "BL_PitchPart", "symbols": ["BL_PP_Degree"], "postprocess": id}, + {"name": "BL_PitchPart", "symbols": ["BL_PP_Chord"], "postprocess": id}, + {"name": "BL_PP_Degree", "symbols": ["NumberLiteral"], "postprocess": d => ({degree: d[0]})}, + {"name": "BL_PP_Degree", "symbols": ["BL_PP_Anchor"], "postprocess": d => ({anchor: d[0], degree: 1})}, + {"name": "BL_PP_Degree", "symbols": ["BL_PP_Anchor", "NumberLiteral"], "postprocess": d => ({anchor: d[0], degree: d[1]})}, + {"name": "BL_PP_Chord", "symbols": [{"literal":"c"}], "postprocess": d => ({chord: true, degree: 1})}, + {"name": "BL_PP_Chord", "symbols": ["BL_PP_Degree", {"literal":"c"}], "postprocess": d => ({chord: true, anchor: d[0].anchor, degree: d[0].degree})}, + {"name": "BL_PP_Chord", "symbols": [{"literal":"c"}, "BL_PP_Roll"], "postprocess": d => ({chord: true, roll: d[1], degree: 1})}, + {"name": "BL_PP_Chord", "symbols": ["BL_PP_Degree", {"literal":"c"}, "BL_PP_Roll"], "postprocess": d => ({chord: true, roll: d[2], anchor: d[0].anchor, degree: d[0].degree})}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"k"}], "postprocess": d => 'KEY'}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"n"}], "postprocess": d => 'NEXT'}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"s"}], "postprocess": d => 'STEP'}, + {"name": "BL_PP_Anchor", "symbols": [{"literal":"a"}], "postprocess": d => 'ARPEGGIATE'}, + {"name": "BL_PP_Roll", "symbols": [{"literal":"r"}], "postprocess": d => 'ROLL_UP'}, + {"name": "BL_PP_Roll", "symbols": [{"literal":"r"}, {"literal":"d"}], "postprocess": d => 'ROLL_DOWN'}, + {"name": "BL_OctavePart", "symbols": ["NumberLiteral"], "postprocess": id}, + {"name": "DrumBeatGroupLiteral", "symbols": ["StringLiteral", "_?", "BeatGroupLiteral"], "postprocess": d => new DrumBeatGroupLiteral(d[0], d[2])}, + {"name": "DrumBeatGroupLiteral", "symbols": ["StringLiteral", "_?", "FunctionCallExpression"], "postprocess": d => new DrumBeatGroupLiteral(d[0], d[2])}, + {"name": "DrumBeatLiteral", "symbols": ["NumberLiteral"], "postprocess": d => new DrumBeatLiteral({time: d[0]})}, + {"name": "DrumBeatLiteral", "symbols": ["NumberLiteral", {"literal":"a"}], "postprocess": d => new DrumBeatLiteral({time: d[0], accented: true})}, + {"name": "NumericExpression", "symbols": ["NE_addsub"], "postprocess": id}, + {"name": "NE_parens", "symbols": [{"literal":"("}, "NE_addsub", {"literal":")"}], "postprocess": d => d[1]}, + {"name": "NE_parens", "symbols": ["NumberLiteral"], "postprocess": id}, + {"name": "NE_muldiv", "symbols": ["NE_muldiv", {"literal":"*"}, "NE_parens"], "postprocess": d => (d[0] * d[2])}, + {"name": "NE_muldiv", "symbols": ["NE_muldiv", {"literal":"/"}, "NE_parens"], "postprocess": d => (d[0] / d[2])}, + {"name": "NE_muldiv", "symbols": ["NE_parens"], "postprocess": id}, + {"name": "NE_addsub", "symbols": ["NE_addsub", {"literal":"+"}, "NE_muldiv"], "postprocess": d => (d[0] + d[2])}, + {"name": "NE_addsub", "symbols": ["NE_addsub", {"literal":"-"}, "NE_muldiv"], "postprocess": d => (d[0] - d[2])}, + {"name": "NE_addsub", "symbols": ["NE_muldiv"], "postprocess": id}, + {"name": "Identifier", "symbols": [(lexer.has("identifier") ? {type: "identifier"} : identifier)], "postprocess": d => d[0].value}, + {"name": "NumberLiteral", "symbols": [(lexer.has("number") ? {type: "number"} : number)], "postprocess": d => Number(d[0].value)}, + {"name": "NumberLiteral", "symbols": [(lexer.has("beat_number") ? {type: "beat_number"} : beat_number)], "postprocess": d => Number(d[0].value)}, + {"name": "BooleanLiteral", "symbols": [(lexer.has("boolean") ? {type: "boolean"} : boolean)], "postprocess": d => Boolean(d[0].value)}, + {"name": "StringLiteral", "symbols": [(lexer.has("quoted_string") ? {type: "quoted_string"} : quoted_string)], "postprocess": d => d[0].value.slice(1, -1)}, + {"name": "_?$ebnf$1", "symbols": ["_"], "postprocess": id}, + {"name": "_?$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_?", "symbols": ["_?$ebnf$1"], "postprocess": () => null}, + {"name": "_", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": () => null}, + {"name": "_", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": () => null}, + {"name": "_$ebnf$1", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": id}, + {"name": "_$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$2$subexpression$1$ebnf$1", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": id}, + {"name": "_$ebnf$2$subexpression$1$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$2$subexpression$1", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$2$subexpression$1$ebnf$1"]}, + {"name": "_$ebnf$2", "symbols": ["_$ebnf$2$subexpression$1"]}, + {"name": "_$ebnf$2$subexpression$2$ebnf$1", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": id}, + {"name": "_$ebnf$2$subexpression$2$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$2$subexpression$2", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$2$subexpression$2$ebnf$1"]}, + {"name": "_$ebnf$2", "symbols": ["_$ebnf$2", "_$ebnf$2$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "_", "symbols": ["_$ebnf$1", "_$ebnf$2"], "postprocess": () => null}, + {"name": "_$ebnf$3", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": id}, + {"name": "_$ebnf$3", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$4$subexpression$1$ebnf$1", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": id}, + {"name": "_$ebnf$4$subexpression$1$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$4$subexpression$1", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$4$subexpression$1$ebnf$1"]}, + {"name": "_$ebnf$4", "symbols": ["_$ebnf$4$subexpression$1"]}, + {"name": "_$ebnf$4$subexpression$2$ebnf$1", "symbols": [(lexer.has("beat_ws") ? {type: "beat_ws"} : beat_ws)], "postprocess": id}, + {"name": "_$ebnf$4$subexpression$2$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "_$ebnf$4$subexpression$2", "symbols": [(lexer.has("comment") ? {type: "comment"} : comment), "_$ebnf$4$subexpression$2$ebnf$1"]}, + {"name": "_$ebnf$4", "symbols": ["_$ebnf$4", "_$ebnf$4$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}}, + {"name": "_", "symbols": ["_$ebnf$3", "_$ebnf$4"], "postprocess": () => null} +]; +let ParserStart = "main"; +var grammar = { Lexer, ParserRules, ParserStart }; + +/** + * Parses a string into a set of possible abstract systax trees (ASTs) trees of + * objects representing the syntax of the file. + * @param {string} data The string to parse + * @return {Promise..} A promise that resolves to an array + * of parsings, each of which is an AST. (Ideally there should be 1 parsing.) + * + * See ast_nodes.js or the grammar itself for an idea of what the nodes in the + * tree might look like. + * @private + */ +function getPossibleParses(data) { + return __awaiter(this, void 0, void 0, function* () { + // Create a Parser object from our grammar. + // (I don't think you can reset the parser so make a new one each time) + const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar)); + try { + parser.feed(data); + return parser.results; + } + catch (err) { + // Because tabs screw up the formatting of SyntaxError messages. + err.message = err.message.replace(/\t/g, ' '); + throw err; + } + }); +} +/** + * Parse a string into an Abstract Syntax Tree (AST) -- a tree of objects + * representing the syntax of the file. + * @param {string} data The string to parse + * @return {Promise.} The Abstract Systax Tree (AST). + */ +function parse(data) { + return __awaiter(this, void 0, void 0, function* () { + const parses = yield getPossibleParses(data); + if (!parses.length) { + throw new SyntaxError('Something went wrong, input not parseable.'); + } + return parses[0]; + }); +} + +class PlaybackStyle { + /** + * Set the main ast (the one that plays all its instruments by default). + * @param {ast.GlobalScope} main the main ast + * @param {Map.} asts A map of asts by their path + */ + constructor(mainPath) { + this.mainPath = mainPath; + this.ASTs = new Map(); + this.initialized = false; + } + /** + * Parse each file, pull its dependencies, put it all in a cache, rinse and + * repeat. + * @private + */ + _loadDependencies() { + return __awaiter(this, void 0, void 0, function* () { + let pendingDependencies = [this.mainPath]; + let dependencyPath; + // @TODO: verify that dependencies have compatible time signature to main + while (dependencyPath = pendingDependencies.pop()) { + let rawfile; + try { + rawfile = yield load(dependencyPath); + } + catch (e) { + throw new Error(`Couldn't locate imported style "${dependencyPath}".`); + } + let ast = yield parse(rawfile); + this.ASTs.set(dependencyPath, ast); + ast.init(); + for (let newDependency of ast.dependencies) { + if (!this.ASTs.has(newDependency)) { + pendingDependencies.push(newDependency); + } + } + } + this.main = this.ASTs.get(this.mainPath); + }); + } + _link() { + this.main.link(this.ASTs); + } + /** + * Initialize the style, which includes loading dependencies and linking + * track/pattern calls. Must be called before compiling/playing. + */ + init() { + return __awaiter(this, void 0, void 0, function* () { + yield this._loadDependencies(); + this._link(); + this.initialized = true; + }); + } + /** + * Compile a song into a set of MIDI-like note instructions. + * @param {Song} song A Playback Song (notochord????) + * @returns {NoteSet.} An array-like object containing MIDI-like note + * instructions. + */ + compile(song) { + if (!this.initialized) { + throw new Error('PlayBack style must be initialized before compiling'); + } + let songIterator = song[Symbol.iterator](); + let instruments = this.getInstruments(); + let notes = new Map(); + let beatsPerMeasure = this.main.vars.get('time-signature')[0]; + let totalPastBeats = 0; + for (let instrument of instruments) + notes.set(instrument, new NoteSet()); + let nextValue; + while (nextValue = songIterator.next(), nextValue.done == false) { + let thisMeasureTracks = this.main.execute(songIterator); + for (let [instrument, thisMeasureNotes] of thisMeasureTracks) { + for (let note of thisMeasureNotes) { + note.time += totalPastBeats; + if (this.main.vars.get('swing')) { + let int_part = Math.floor(note.time); + let float_part = note.time - int_part; + if (float_part <= 0.5) { + float_part *= 2; + float_part = (2 / 3) * float_part; + } + else { + float_part = 2 * (float_part - 0.5); + float_part = (2 / 3) + ((1 / 3) * float_part); + } + note.time = int_part + float_part; + } + } + notes.get(instrument).push(...thisMeasureNotes); + } + totalPastBeats += beatsPerMeasure; + } + return notes; + } + getInstruments() { + return this.main.getInstruments(); + } +} + +let moduleDefs = {1:[function(require,module,exports){ + + var load = require('audio-loader'); + var player = require('sample-player'); + + /** + * Load a soundfont instrument. It returns a promise that resolves to a + * instrument object. + * + * The instrument object returned by the promise has the following properties: + * + * - name: the instrument name + * - play: A function to play notes from the buffer with the signature + * `play(note, time, duration, options)` + * + * + * The valid options are: + * + * - `format`: the soundfont format. 'mp3' by default. Can be 'ogg' + * - `soundfont`: the soundfont name. 'MusyngKite' by default. Can be 'FluidR3_GM' + * - `nameToUrl` : a function to convert from instrument names to URL + * - `destination`: by default Soundfont uses the `audioContext.destination` but you can override it. + * - `gain`: the gain of the player (1 by default) + * - `notes`: an array of the notes to decode. It can be an array of strings + * with note names or an array of numbers with midi note numbers. This is a + * performance option: since decoding mp3 is a cpu intensive process, you can limit + * limit the number of notes you want and reduce the time to load the instrument. + * + * @param {AudioContext} ac - the audio context + * @param {String} name - the instrument name. For example: 'acoustic_grand_piano' + * @param {Object} options - (Optional) the same options as Soundfont.loadBuffers + * @return {Promise} + * + * @example + * var Soundfont = require('sounfont-player') + * Soundfont.instrument('marimba').then(function (marimba) { + * marimba.play('C4') + * }) + */ + function instrument (ac, name, options) { + if (arguments.length === 1) return function (n, o) { return instrument(ac, n, o) } + var opts = options || {}; + var isUrl = opts.isSoundfontURL || isSoundfontURL; + var toUrl = opts.nameToUrl || nameToUrl; + var url = isUrl(name) ? name : toUrl(name, opts.soundfont, opts.format); + + return load(ac, url, { only: opts.only || opts.notes }).then(function (buffers) { + var p = player(ac, buffers, opts).connect(opts.destination ? opts.destination : ac.destination); + p.url = url; + p.name = name; + return p + }) + } + + function isSoundfontURL (name) { + return /\.js(\?.*)?$/i.test(name) + } + + /** + * Given an instrument name returns a URL to to the Benjamin Gleitzman's + * package of [pre-rendered sound fonts](https://github.com/gleitz/midi-js-soundfonts) + * + * @param {String} name - instrument name + * @param {String} soundfont - (Optional) the soundfont name. One of 'FluidR3_GM' + * or 'MusyngKite' ('MusyngKite' by default) + * @param {String} format - (Optional) Can be 'mp3' or 'ogg' (mp3 by default) + * @returns {String} the Soundfont file url + * @example + * var Soundfont = require('soundfont-player') + * Soundfont.nameToUrl('marimba', 'mp3') + */ + function nameToUrl (name, sf, format) { + format = format === 'ogg' ? format : 'mp3'; + sf = sf === 'FluidR3_GM' ? sf : 'MusyngKite'; + return 'https://gleitz.github.io/midi-js-soundfonts/' + sf + '/' + name + '-' + format + '.js' + } + + // In the 1.0.0 release it will be: + // var Soundfont = {} + var Soundfont = require('./legacy'); + Soundfont.instrument = instrument; + Soundfont.nameToUrl = nameToUrl; + + if (typeof module === 'object' && module.exports) module.exports = Soundfont; + if (typeof window !== 'undefined') window.Soundfont = Soundfont; + + },{"./legacy":2,"audio-loader":6,"sample-player":10}],2:[function(require,module,exports){ + + var parser = require('note-parser'); + + /** + * Create a Soundfont object + * + * @param {AudioContext} context - the [audio context](https://developer.mozilla.org/en/docs/Web/API/AudioContext) + * @param {Function} nameToUrl - (Optional) a function that maps the sound font name to the url + * @return {Soundfont} a soundfont object + */ + function Soundfont (ctx, nameToUrl) { + console.warn('new Soundfont() is deprected'); + console.log('Please use Soundfont.instrument() instead of new Soundfont().instrument()'); + if (!(this instanceof Soundfont)) return new Soundfont(ctx) + + this.nameToUrl = nameToUrl || Soundfont.nameToUrl; + this.ctx = ctx; + this.instruments = {}; + this.promises = []; + } + + Soundfont.prototype.onready = function (callback) { + console.warn('deprecated API'); + console.log('Please use Promise.all(Soundfont.instrument(), Soundfont.instrument()).then() instead of new Soundfont().onready()'); + Promise.all(this.promises).then(callback); + }; + + Soundfont.prototype.instrument = function (name, options) { + console.warn('new Soundfont().instrument() is deprecated.'); + console.log('Please use Soundfont.instrument() instead.'); + var ctx = this.ctx; + name = name || 'default'; + if (name in this.instruments) return this.instruments[name] + var inst = {name: name, play: oscillatorPlayer(ctx, options)}; + this.instruments[name] = inst; + if (name !== 'default') { + var promise = Soundfont.instrument(ctx, name, options).then(function (instrument) { + inst.play = instrument.play; + return inst + }); + this.promises.push(promise); + inst.onready = function (cb) { + console.warn('onready is deprecated. Use Soundfont.instrument().then()'); + promise.then(cb); + }; + } else { + inst.onready = function (cb) { + console.warn('onready is deprecated. Use Soundfont.instrument().then()'); + cb(); + }; + } + return inst + }; + + /* + * Load the buffers of a given instrument name. It returns a promise that resolves + * to a hash with midi note numbers as keys, and audio buffers as values. + * + * @param {AudioContext} ac - the audio context + * @param {String} name - the instrument name (it accepts an url if starts with "http") + * @param {Object} options - (Optional) options object + * @return {Promise} a promise that resolves to a Hash of { midiNoteNum: } + * + * The options object accepts the following keys: + * + * - nameToUrl {Function}: a function to convert from instrument names to urls. + * By default it uses Benjamin Gleitzman's package of + * [pre-rendered sound fonts](https://github.com/gleitz/midi-js-soundfonts) + * - notes {Array}: the list of note names to be decoded (all by default) + * + * @example + * var Soundfont = require('soundfont-player') + * Soundfont.loadBuffers(ctx, 'acoustic_grand_piano').then(function(buffers) { + * buffers[60] // => An corresponding to note C4 + * }) + */ + function loadBuffers (ac, name, options) { + console.warn('Soundfont.loadBuffers is deprecate.'); + console.log('Use Soundfont.instrument(..) and get buffers properties from the result.'); + return Soundfont.instrument(ac, name, options).then(function (inst) { + return inst.buffers + }) + } + Soundfont.loadBuffers = loadBuffers; + + /** + * Returns a function that plays an oscillator + * + * @param {AudioContext} ac - the audio context + * @param {Hash} defaultOptions - (Optional) a hash of options: + * - vcoType: the oscillator type (default: 'sine') + * - gain: the output gain value (default: 0.4) + * - destination: the player destination (default: ac.destination) + */ + function oscillatorPlayer (ctx, defaultOptions) { + defaultOptions = defaultOptions || {}; + return function (note, time, duration, options) { + console.warn('The oscillator player is deprecated.'); + console.log('Starting with version 0.9.0 you will have to wait until the soundfont is loaded to play sounds.'); + var midi = note > 0 && note < 129 ? +note : parser.midi(note); + var freq = midi ? parser.midiToFreq(midi, 440) : null; + if (!freq) return + + duration = duration || 0.2; + + options = options || {}; + var destination = options.destination || defaultOptions.destination || ctx.destination; + var vcoType = options.vcoType || defaultOptions.vcoType || 'sine'; + var gain = options.gain || defaultOptions.gain || 0.4; + + var vco = ctx.createOscillator(); + vco.type = vcoType; + vco.frequency.value = freq; + + /* VCA */ + var vca = ctx.createGain(); + vca.gain.value = gain; + + /* Connections */ + vco.connect(vca); + vca.connect(destination); + + vco.start(time); + if (duration > 0) vco.stop(time + duration); + return vco + } + } + + /** + * Given a note name, return the note midi number + * + * @name noteToMidi + * @function + * @param {String} noteName + * @return {Integer} the note midi number or null if not a valid note name + */ + Soundfont.noteToMidi = parser.midi; + + module.exports = Soundfont; + + },{"note-parser":8}],3:[function(require,module,exports){ + module.exports = ADSR; + + function ADSR(audioContext){ + var node = audioContext.createGain(); + + var voltage = node._voltage = getVoltage(audioContext); + var value = scale(voltage); + var startValue = scale(voltage); + var endValue = scale(voltage); + + node._startAmount = scale(startValue); + node._endAmount = scale(endValue); + + node._multiplier = scale(value); + node._multiplier.connect(node); + node._startAmount.connect(node); + node._endAmount.connect(node); + + node.value = value.gain; + node.startValue = startValue.gain; + node.endValue = endValue.gain; + + node.startValue.value = 0; + node.endValue.value = 0; + + Object.defineProperties(node, props); + return node + } + + var props = { + + attack: { value: 0, writable: true }, + decay: { value: 0, writable: true }, + sustain: { value: 1, writable: true }, + release: {value: 0, writable: true }, + + getReleaseDuration: { + value: function(){ + return this.release + } + }, + + start: { + value: function(at){ + var target = this._multiplier.gain; + var startAmount = this._startAmount.gain; + var endAmount = this._endAmount.gain; + + this._voltage.start(at); + this._decayFrom = this._decayFrom = at+this.attack; + this._startedAt = at; + + var sustain = this.sustain; + + target.cancelScheduledValues(at); + startAmount.cancelScheduledValues(at); + endAmount.cancelScheduledValues(at); + + endAmount.setValueAtTime(0, at); + + if (this.attack){ + target.setValueAtTime(0, at); + target.linearRampToValueAtTime(1, at + this.attack); + + startAmount.setValueAtTime(1, at); + startAmount.linearRampToValueAtTime(0, at + this.attack); + } else { + target.setValueAtTime(1, at); + startAmount.setValueAtTime(0, at); + } + + if (this.decay){ + target.setTargetAtTime(sustain, this._decayFrom, getTimeConstant(this.decay)); + } + } + }, + + stop: { + value: function(at, isTarget){ + if (isTarget){ + at = at - this.release; + } + + var endTime = at + this.release; + if (this.release){ + + var target = this._multiplier.gain; + var startAmount = this._startAmount.gain; + var endAmount = this._endAmount.gain; + + target.cancelScheduledValues(at); + startAmount.cancelScheduledValues(at); + endAmount.cancelScheduledValues(at); + + var expFalloff = getTimeConstant(this.release); + + // truncate attack (required as linearRamp is removed by cancelScheduledValues) + if (this.attack && at < this._decayFrom){ + var valueAtTime = getValue(0, 1, this._startedAt, this._decayFrom, at); + target.linearRampToValueAtTime(valueAtTime, at); + startAmount.linearRampToValueAtTime(1-valueAtTime, at); + startAmount.setTargetAtTime(0, at, expFalloff); + } + + endAmount.setTargetAtTime(1, at, expFalloff); + target.setTargetAtTime(0, at, expFalloff); + } + + this._voltage.stop(endTime); + return endTime + } + }, + + onended: { + get: function(){ + return this._voltage.onended + }, + set: function(value){ + this._voltage.onended = value; + } + } + + }; + + var flat = new Float32Array([1,1]); + function getVoltage(context){ + var voltage = context.createBufferSource(); + var buffer = context.createBuffer(1, 2, context.sampleRate); + buffer.getChannelData(0).set(flat); + voltage.buffer = buffer; + voltage.loop = true; + return voltage + } + + function scale(node){ + var gain = node.context.createGain(); + node.connect(gain); + return gain + } + + function getTimeConstant(time){ + return Math.log(time+1)/Math.log(100) + } + + function getValue(start, end, fromTime, toTime, at){ + var difference = end - start; + var time = toTime - fromTime; + var truncateTime = at - fromTime; + var phase = truncateTime / time; + var value = start + phase * difference; + + if (value <= start) { + value = start; + } + if (value >= end) { + value = end; + } + + return value + } + + },{}],4:[function(require,module,exports){ + + // DECODE UTILITIES + function b64ToUint6 (nChr) { + return nChr > 64 && nChr < 91 ? nChr - 65 + : nChr > 96 && nChr < 123 ? nChr - 71 + : nChr > 47 && nChr < 58 ? nChr + 4 + : nChr === 43 ? 62 + : nChr === 47 ? 63 + : 0 + } + + // Decode Base64 to Uint8Array + // --------------------------- + function decode (sBase64, nBlocksSize) { + var sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ''); + var nInLen = sB64Enc.length; + var nOutLen = nBlocksSize + ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize + : nInLen * 3 + 1 >> 2; + var taBytes = new Uint8Array(nOutLen); + + for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) { + nMod4 = nInIdx & 3; + nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4; + if (nMod4 === 3 || nInLen - nInIdx === 1) { + for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) { + taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255; + } + nUint24 = 0; + } + } + return taBytes + } + + module.exports = { decode: decode }; + + },{}],5:[function(require,module,exports){ + + /** + * Given a url and a return type, returns a promise to the content of the url + * Basically it wraps a XMLHttpRequest into a Promise + * + * @param {String} url + * @param {String} type - can be 'text' or 'arraybuffer' + * @return {Promise} + */ + module.exports = function (url, type) { + return new Promise(function (done, reject) { + var req = new XMLHttpRequest(); + if (type) req.responseType = type; + + req.open('GET', url); + req.onload = function () { + req.status === 200 ? done(req.response) : reject(Error(req.statusText)); + }; + req.onerror = function () { reject(Error('Network Error')); }; + req.send(); + }) + }; + + },{}],6:[function(require,module,exports){ + + var base64 = require('./base64'); + var fetch = require('./fetch'); + + // Given a regex, return a function that test if against a string + function fromRegex (r) { + return function (o) { return typeof o === 'string' && r.test(o) } + } + // Try to apply a prefix to a name + function prefix (pre, name) { + return typeof pre === 'string' ? pre + name + : typeof pre === 'function' ? pre(name) + : name + } + + /** + * Load one or more audio files + * + * + * Possible option keys: + * + * - __from__ {Function|String}: a function or string to convert from file names to urls. + * If is a string it will be prefixed to the name: + * `load(ac, 'snare.mp3', { from: 'http://audio.net/samples/' })` + * If it's a function it receives the file name and should return the url as string. + * - __only__ {Array} - when loading objects, if provided, only the given keys + * will be included in the decoded object: + * `load(ac, 'piano.json', { only: ['C2', 'D2'] })` + * + * @param {AudioContext} ac - the audio context + * @param {Object} source - the object to be loaded + * @param {Object} options - (Optional) the load options for that object + * @param {Object} defaultValue - (Optional) the default value to return as + * in a promise if not valid loader found + */ + function load (ac, source, options, defVal) { + var loader = + // Basic audio loading + isArrayBuffer(source) ? loadArrayBuffer + : isAudioFileName(source) ? loadAudioFile + : isPromise(source) ? loadPromise + // Compound objects + : isArray(source) ? loadArrayData + : isObject(source) ? loadObjectData + : isJsonFileName(source) ? loadJsonFile + // Base64 encoded audio + : isBase64Audio(source) ? loadBase64Audio + : isJsFileName(source) ? loadMidiJSFile + : null; + + var opts = options || {}; + return loader ? loader(ac, source, opts) + : defVal ? Promise.resolve(defVal) + : Promise.reject('Source not valid (' + source + ')') + } + load.fetch = fetch; + + // BASIC AUDIO LOADING + // =================== + + // Load (decode) an array buffer + function isArrayBuffer (o) { return o instanceof ArrayBuffer } + function loadArrayBuffer (ac, array, options) { + return new Promise(function (done, reject) { + ac.decodeAudioData(array, + function (buffer) { done(buffer); }, + function () { reject("Can't decode audio data (" + array.slice(0, 30) + '...)'); } + ); + }) + } + + // Load an audio filename + var isAudioFileName = fromRegex(/\.(mp3|wav|ogg)(\?.*)?$/i); + function loadAudioFile (ac, name, options) { + var url = prefix(options.from, name); + return load(ac, load.fetch(url, 'arraybuffer'), options) + } + + // Load the result of a promise + function isPromise (o) { return o && typeof o.then === 'function' } + function loadPromise (ac, promise, options) { + return promise.then(function (value) { + return load(ac, value, options) + }) + } + + // COMPOUND OBJECTS + // ================ + + // Try to load all the items of an array + var isArray = Array.isArray; + function loadArrayData (ac, array, options) { + return Promise.all(array.map(function (data) { + return load(ac, data, options, data) + })) + } + + // Try to load all the values of a key/value object + function isObject (o) { return o && typeof o === 'object' } + function loadObjectData (ac, obj, options) { + var dest = {}; + var promises = Object.keys(obj).map(function (key) { + if (options.only && options.only.indexOf(key) === -1) return null + var value = obj[key]; + return load(ac, value, options, value).then(function (audio) { + dest[key] = audio; + }) + }); + return Promise.all(promises).then(function () { return dest }) + } + + // Load the content of a JSON file + var isJsonFileName = fromRegex(/\.json(\?.*)?$/i); + function loadJsonFile (ac, name, options) { + var url = prefix(options.from, name); + return load(ac, load.fetch(url, 'text').then(JSON.parse), options) + } + + // BASE64 ENCODED FORMATS + // ====================== + + // Load strings with Base64 encoded audio + var isBase64Audio = fromRegex(/^data:audio/); + function loadBase64Audio (ac, source, options) { + var i = source.indexOf(','); + return load(ac, base64.decode(source.slice(i + 1)).buffer, options) + } + + // Load .js files with MidiJS soundfont prerendered audio + var isJsFileName = fromRegex(/\.js(\?.*)?$/i); + function loadMidiJSFile (ac, name, options) { + var url = prefix(options.from, name); + return load(ac, load.fetch(url, 'text').then(midiJsToJson), options) + } + + // convert a MIDI.js javascript soundfont file to json + function midiJsToJson (data) { + var begin = data.indexOf('MIDI.Soundfont.'); + if (begin < 0) throw Error('Invalid MIDI.js Soundfont format') + begin = data.indexOf('=', begin) + 2; + var end = data.lastIndexOf(','); + return JSON.parse(data.slice(begin, end) + '}') + } + + if (typeof module === 'object' && module.exports) module.exports = load; + if (typeof window !== 'undefined') window.loadAudio = load; + + },{"./base64":4,"./fetch":5}],7:[function(require,module,exports){ + (function (global){ + (function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e();}else if(typeof define==="function"&&define.amd){define([],e);}else{var t;if(typeof window!=="undefined"){t=window;}else if(typeof global!=="undefined"){t=global;}else if(typeof self!=="undefined"){t=self;}else{t=this;}t.midimessage=e();}})(function(){return function o(e,t,s){function a(n,i){if(!t[n]){if(!e[n]){var l=typeof require=="function"&&require;if(!i&&l)return l(n,!0);if(r)return r(n,!0);var h=new Error("Cannot find module '"+n+"'");throw h.code="MODULE_NOT_FOUND",h}var c=t[n]={exports:{}};e[n][0].call(c.exports,function(t){var s=e[n][1][t];return a(s?s:t)},c,c.exports,o,e,t,s);}return t[n].exports}var r=typeof require=="function"&&require;for(var n=0;n6?null:C.charAt(t)+f(n)+a(r)}function p(t){if((r(t)||e(t))&&t>=0&&t<128)return +t;var n=i(t);return n&&u(n.midi)?n.midi:null}function s(t,n){var r=p(t);return null===r?null:c(r,n)}function d(t){return (i(t)||{}).letter}function m(t){return (i(t)||{}).acc}function h(t){return (i(t)||{}).pc}function v(t){return (i(t)||{}).step}function g(t){return (i(t)||{}).alt}function x(t){return (i(t)||{}).chroma}function y(t){return (i(t)||{}).oct}var b=/^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)\s*$/,A=[0,2,4,5,7,9,11],C="CDEFGAB";t.regex=o,t.parse=i,t.build=l,t.midi=p,t.freq=s,t.letter=d,t.acc=m,t.pc=h,t.step=v,t.alt=g,t.chroma=x,t.oct=y;}); + + + },{}],9:[function(require,module,exports){ + + module.exports = function (player) { + /** + * Adds a listener of an event + * @chainable + * @param {String} event - the event name + * @param {Function} callback - the event handler + * @return {SamplePlayer} the player + * @example + * player.on('start', function(time, note) { + * console.log(time, note) + * }) + */ + player.on = function (event, cb) { + if (arguments.length === 1 && typeof event === 'function') return player.on('event', event) + var prop = 'on' + event; + var old = player[prop]; + player[prop] = old ? chain(old, cb) : cb; + return player + }; + return player + }; + + function chain (fn1, fn2) { + return function (a, b, c, d) { fn1(a, b, c, d); fn2(a, b, c, d); } + } + + },{}],10:[function(require,module,exports){ + + var player = require('./player'); + var events = require('./events'); + var notes = require('./notes'); + var scheduler = require('./scheduler'); + var midi = require('./midi'); + + function SamplePlayer (ac, source, options) { + return midi(scheduler(notes(events(player(ac, source, options))))) + } + + if (typeof module === 'object' && module.exports) module.exports = SamplePlayer; + if (typeof window !== 'undefined') window.SamplePlayer = SamplePlayer; + + },{"./events":9,"./midi":11,"./notes":12,"./player":13,"./scheduler":14}],11:[function(require,module,exports){ + var midimessage = require('midimessage'); + + module.exports = function (player) { + /** + * Connect a player to a midi input + * + * The options accepts: + * + * - channel: the channel to listen to. Listen to all channels by default. + * + * @param {MIDIInput} input + * @param {Object} options - (Optional) + * @return {SamplePlayer} the player + * @example + * var piano = player(...) + * window.navigator.requestMIDIAccess().then(function (midiAccess) { + * midiAccess.inputs.forEach(function (midiInput) { + * piano.listenToMidi(midiInput) + * }) + * }) + */ + player.listenToMidi = function (input, options) { + var started = {}; + var opts = options || {}; + var gain = opts.gain || function (vel) { return vel / 127 }; + + input.onmidimessage = function (msg) { + var mm = msg.messageType ? msg : midimessage(msg); + if (mm.messageType === 'noteon' && mm.velocity === 0) { + mm.messageType = 'noteoff'; + } + if (opts.channel && mm.channel !== opts.channel) return + + switch (mm.messageType) { + case 'noteon': + started[mm.key] = player.play(mm.key, 0, { gain: gain(mm.velocity) }); + break + case 'noteoff': + if (started[mm.key]) { + started[mm.key].stop(); + delete started[mm.key]; + } + break + } + }; + return player + }; + return player + }; + + },{"midimessage":7}],12:[function(require,module,exports){ + + var note = require('note-parser'); + var isMidi = function (n) { return n !== null && n !== [] && n >= 0 && n < 129 }; + var toMidi = function (n) { return isMidi(n) ? +n : note.midi(n) }; + + // Adds note name to midi conversion + module.exports = function (player) { + if (player.buffers) { + var map = player.opts.map; + var toKey = typeof map === 'function' ? map : toMidi; + var mapper = function (name) { + return name ? toKey(name) || name : null + }; + + player.buffers = mapBuffers(player.buffers, mapper); + var start = player.start; + player.start = function (name, when, options) { + var key = mapper(name); + var dec = key % 1; + if (dec) { + key = Math.floor(key); + options = Object.assign(options || {}, { cents: Math.floor(dec * 100) }); + } + return start(key, when, options) + }; + } + return player + }; + + function mapBuffers (buffers, toKey) { + return Object.keys(buffers).reduce(function (mapped, name) { + mapped[toKey(name)] = buffers[name]; + return mapped + }, {}) + } + + },{"note-parser":15}],13:[function(require,module,exports){ + + var ADSR = require('adsr'); + + var EMPTY = {}; + var DEFAULTS = { + gain: 1, + attack: 0.01, + decay: 0.1, + sustain: 0.9, + release: 0.3, + loop: false, + cents: 0, + loopStart: 0, + loopEnd: 0 + }; + + /** + * Create a sample player. + * + * @param {AudioContext} ac - the audio context + * @param {ArrayBuffer|Object} source + * @param {Onject} options - (Optional) an options object + * @return {player} the player + * @example + * var SamplePlayer = require('sample-player') + * var ac = new AudioContext() + * var snare = SamplePlayer(ac, ) + * snare.play() + */ + function SamplePlayer (ac, source, options) { + var connected = false; + var nextId = 0; + var tracked = {}; + var out = ac.createGain(); + out.gain.value = 1; + + var opts = Object.assign({}, DEFAULTS, options); + + /** + * @namespace + */ + var player = { context: ac, out: out, opts: opts }; + if (source instanceof AudioBuffer) player.buffer = source; + else player.buffers = source; + + /** + * Start a sample buffer. + * + * The returned object has a function `stop(when)` to stop the sound. + * + * @param {String} name - the name of the buffer. If the source of the + * SamplePlayer is one sample buffer, this parameter is not required + * @param {Float} when - (Optional) when to start (current time if by default) + * @param {Object} options - additional sample playing options + * @return {AudioNode} an audio node with a `stop` function + * @example + * var sample = player(ac, ).connect(ac.destination) + * sample.start() + * sample.start(5, { gain: 0.7 }) // name not required since is only one AudioBuffer + * @example + * var drums = player(ac, { snare: , kick: , ... }).connect(ac.destination) + * drums.start('snare') + * drums.start('snare', 0, { gain: 0.3 }) + */ + player.start = function (name, when, options) { + // if only one buffer, reorder arguments + if (player.buffer && name !== null) return player.start(null, name, when) + + var buffer = name ? player.buffers[name] : player.buffer; + if (!buffer) { + console.warn('Buffer ' + name + ' not found.'); + return + } else if (!connected) { + console.warn('SamplePlayer not connected to any node.'); + return + } + + var opts = options || EMPTY; + when = Math.max(ac.currentTime, when || 0); + player.emit('start', when, name, opts); + var node = createNode(name, buffer, opts); + node.id = track(name, node); + node.env.start(when); + node.source.start(when); + player.emit('started', when, node.id, node); + if (opts.duration) node.stop(when + opts.duration); + return node + }; + + // NOTE: start will be override so we can't copy the function reference + // this is obviously not a good design, so this code will be gone soon. + /** + * An alias for `player.start` + * @see player.start + * @since 0.3.0 + */ + player.play = function (name, when, options) { + return player.start(name, when, options) + }; + + /** + * Stop some or all samples + * + * @param {Float} when - (Optional) an absolute time in seconds (or currentTime + * if not specified) + * @param {Array} nodes - (Optional) an array of nodes or nodes ids to stop + * @return {Array} an array of ids of the stoped samples + * + * @example + * var longSound = player(ac, ).connect(ac.destination) + * longSound.start(ac.currentTime) + * longSound.start(ac.currentTime + 1) + * longSound.start(ac.currentTime + 2) + * longSound.stop(ac.currentTime + 3) // stop the three sounds + */ + player.stop = function (when, ids) { + var node; + ids = ids || Object.keys(tracked); + return ids.map(function (id) { + node = tracked[id]; + if (!node) return null + node.stop(when); + return node.id + }) + }; + /** + * Connect the player to a destination node + * + * @param {AudioNode} destination - the destination node + * @return {AudioPlayer} the player + * @chainable + * @example + * var sample = player(ac, ).connect(ac.destination) + */ + player.connect = function (dest) { + connected = true; + out.connect(dest); + return player + }; + + player.emit = function (event, when, obj, opts) { + if (player.onevent) player.onevent(event, when, obj, opts); + var fn = player['on' + event]; + if (fn) fn(when, obj, opts); + }; + + return player + + // =============== PRIVATE FUNCTIONS ============== // + + function track (name, node) { + node.id = nextId++; + tracked[node.id] = node; + node.source.onended = function () { + var now = ac.currentTime; + node.source.disconnect(); + node.env.disconnect(); + node.disconnect(); + player.emit('ended', now, node.id, node); + }; + return node.id + } + + function createNode (name, buffer, options) { + var node = ac.createGain(); + node.gain.value = 0; // the envelope will control the gain + node.connect(out); + + node.env = envelope(ac, options, opts); + node.env.connect(node.gain); + + node.source = ac.createBufferSource(); + node.source.buffer = buffer; + node.source.connect(node); + node.source.loop = options.loop || opts.loop; + node.source.playbackRate.value = centsToRate(options.cents || opts.cents); + node.source.loopStart = options.loopStart || opts.loopStart; + node.source.loopEnd = options.loopEnd || opts.loopEnd; + node.stop = function (when) { + var time = when || ac.currentTime; + player.emit('stop', time, name); + var stopAt = node.env.stop(time); + node.source.stop(stopAt); + }; + return node + } + } + + function isNum (x) { return typeof x === 'number' } + var PARAMS = ['attack', 'decay', 'sustain', 'release']; + function envelope (ac, options, opts) { + var env = ADSR(ac); + var adsr = options.adsr || opts.adsr; + PARAMS.forEach(function (name, i) { + if (adsr) env[name] = adsr[i]; + else env[name] = options[name] || opts[name]; + }); + env.value.value = isNum(options.gain) ? options.gain + : isNum(opts.gain) ? opts.gain : 1; + return env + } + + /* + * Get playback rate for a given pitch change (in cents) + * Basic [math](http://www.birdsoft.demon.co.uk/music/samplert.htm): + * f2 = f1 * 2^( C / 1200 ) + */ + function centsToRate (cents) { return cents ? Math.pow(2, cents / 1200) : 1 } + + module.exports = SamplePlayer; + + },{"adsr":3}],14:[function(require,module,exports){ + + var isArr = Array.isArray; + var isObj = function (o) { return o && typeof o === 'object' }; + var OPTS = {}; + + module.exports = function (player) { + /** + * Schedule a list of events to be played at specific time. + * + * It supports three formats of events for the events list: + * + * - An array with [time, note] + * - An array with [time, object] + * - An object with { time: ?, [name|note|midi|key]: ? } + * + * @param {Float} time - an absolute time to start (or AudioContext's + * currentTime if provided number is 0) + * @param {Array} events - the events list. + * @return {Array} an array of ids + * + * @example + * // Event format: [time, note] + * var piano = player(ac, ...).connect(ac.destination) + * piano.schedule(0, [ [0, 'C2'], [0.5, 'C3'], [1, 'C4'] ]) + * + * @example + * // Event format: an object { time: ?, name: ? } + * var drums = player(ac, ...).connect(ac.destination) + * drums.schedule(0, [ + * { name: 'kick', time: 0 }, + * { name: 'snare', time: 0.5 }, + * { name: 'kick', time: 1 }, + * { name: 'snare', time: 1.5 } + * ]) + */ + player.schedule = function (time, events) { + var now = player.context.currentTime; + var when = time < now ? now : time; + player.emit('schedule', when, events); + var t, o, note, opts; + return events.map(function (event) { + if (!event) return null + else if (isArr(event)) { + t = event[0]; o = event[1]; + } else { + t = event.time; o = event; + } + + if (isObj(o)) { + note = o.name || o.key || o.note || o.midi || null; + opts = o; + } else { + note = o; + opts = OPTS; + } + + return player.start(note, when + (t || 0), opts) + }) + }; + return player + }; + + },{}],15:[function(require,module,exports){ + + var REGEX = /^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)\s*$/; + /** + * A regex for matching note strings in scientific notation. + * + * @name regex + * @function + * @return {RegExp} the regexp used to parse the note name + * + * The note string should have the form `letter[accidentals][octave][element]` + * where: + * + * - letter: (Required) is a letter from A to G either upper or lower case + * - accidentals: (Optional) can be one or more `b` (flats), `#` (sharps) or `x` (double sharps). + * They can NOT be mixed. + * - octave: (Optional) a positive or negative integer + * - element: (Optional) additionally anything after the duration is considered to + * be the element name (for example: 'C2 dorian') + * + * The executed regex contains (by array index): + * + * - 0: the complete string + * - 1: the note letter + * - 2: the optional accidentals + * - 3: the optional octave + * - 4: the rest of the string (trimmed) + * + * @example + * var parser = require('note-parser') + * parser.regex.exec('c#4') + * // => ['c#4', 'c', '#', '4', ''] + * parser.regex.exec('c#4 major') + * // => ['c#4major', 'c', '#', '4', 'major'] + * parser.regex().exec('CMaj7') + * // => ['CMaj7', 'C', '', '', 'Maj7'] + */ + function regex () { return REGEX } + + var SEMITONES = [0, 2, 4, 5, 7, 9, 11]; + /** + * Parse a note name in scientific notation an return it's components, + * and some numeric properties including midi number and frequency. + * + * @name parse + * @function + * @param {String} note - the note string to be parsed + * @param {Boolean} isTonic - true if the note is the tonic of something. + * If true, en extra tonicOf property is returned. It's false by default. + * @param {Float} tunning - The frequency of A4 note to calculate frequencies. + * By default it 440. + * @return {Object} the parsed note name or null if not a valid note + * + * The parsed note name object will ALWAYS contains: + * - letter: the uppercase letter of the note + * - acc: the accidentals of the note (only sharps or flats) + * - pc: the pitch class (letter + acc) + * - step: s a numeric representation of the letter. It's an integer from 0 to 6 + * where 0 = C, 1 = D ... 6 = B + * - alt: a numeric representation of the accidentals. 0 means no alteration, + * positive numbers are for sharps and negative for flats + * - chroma: a numeric representation of the pitch class. It's like midi for + * pitch classes. 0 = C, 1 = C#, 2 = D ... It can have negative values: -1 = Cb. + * Can detect pitch class enhramonics. + * + * If the note has octave, the parser object will contain: + * - oct: the octave number (as integer) + * - midi: the midi number + * - freq: the frequency (using tuning parameter as base) + * + * If the parameter `isTonic` is set to true, the parsed object will contain: + * - tonicOf: the rest of the string that follows note name (left and right trimmed) + * + * @example + * var parse = require('note-parser').parse + * parse('Cb4') + * // => { letter: 'C', acc: 'b', pc: 'Cb', step: 0, alt: -1, chroma: -1, + * oct: 4, midi: 59, freq: 246.94165062806206 } + * // if no octave, no midi, no freq + * parse('fx') + * // => { letter: 'F', acc: '##', pc: 'F##', step: 3, alt: 2, chroma: 7 }) + */ + function parse (str, isTonic, tuning) { + if (typeof str !== 'string') return null + var m = REGEX.exec(str); + if (!m || !isTonic && m[4]) return null + + var p = { letter: m[1].toUpperCase(), acc: m[2].replace(/x/g, '##') }; + p.pc = p.letter + p.acc; + p.step = (p.letter.charCodeAt(0) + 3) % 7; + p.alt = p.acc[0] === 'b' ? -p.acc.length : p.acc.length; + p.chroma = SEMITONES[p.step] + p.alt; + if (m[3]) { + p.oct = +m[3]; + p.midi = p.chroma + 12 * (p.oct + 1); + p.freq = midiToFreq(p.midi, tuning); + } + if (isTonic) p.tonicOf = m[4]; + return p + } + + /** + * Given a midi number, return its frequency + * @param {Integer} midi - midi note number + * @param {Float} tuning - (Optional) the A4 tuning (440Hz by default) + * @return {Float} frequency in hertzs + */ + function midiToFreq (midi, tuning) { + return Math.pow(2, (midi - 69) / 12) * (tuning || 440) + } + + var parser = { parse: parse, regex: regex, midiToFreq: midiToFreq }; + var FNS = ['letter', 'acc', 'pc', 'step', 'alt', 'chroma', 'oct', 'midi', 'freq']; + FNS.forEach(function (name) { + parser[name] = function (src) { + var p = parse(src); + return p && (typeof p[name] !== 'undefined') ? p[name] : null + }; + }); + + module.exports = parser; + + // extra API docs + /** + * Get midi of a note + * + * @name midi + * @function + * @param {String} note - the note name + * @return {Integer} the midi number of the note or null if not a valid note + * or the note does NOT contains octave + * @example + * var parser = require('note-parser') + * parser.midi('A4') // => 69 + * parser.midi('A') // => null + */ + /** + * Get freq of a note in hertzs (in a well tempered 440Hz A4) + * + * @name freq + * @function + * @param {String} note - the note name + * @return {Float} the freq of the number if hertzs or null if not valid note + * or the note does NOT contains octave + * @example + * var parser = require('note-parser') + * parser.freq('A4') // => 440 + * parser.freq('A') // => null + */ + + },{}]}; + +let modulesByID = {}; +function link(id) { + if(!modulesByID[id]) { + let _module = modulesByID[id] = { exports: {} }; + let _require = function(requiredName) { + let requiredID = moduleDefs[id][1][requiredName]; + return link(requiredID || requiredName); + }; + moduleDefs[id][0].call(_module.exports, _require, _module, _module.exports); + } + return modulesByID[id].exports; +} + +let soundfont = link(1); + +class Player { + /** + * Loads the necessary soundfonts and plays a song in a PlaybackStyle in the + * browser. + * @param {AudioContext=} context If you pass it an AudioContext it'll use + * it. Otherwise it'll make its own. + */ + constructor(context) { + this.style = null; + this.context = context || new AudioContext({ latencyHint: "playback" }); + this.initialized = false; + window.player = this; + } + setStyle(style) { + return __awaiter(this, void 0, void 0, function* () { + this.style = style; + if (!style._initialized) { + yield style.init(); + } + this.initialized = false; + this.soundfonts = new Map(); + let promises = []; + for (let instrument of style.getInstruments()) { + let sfpromise; + if (instrument.startsWith('http://') || instrument.startsWith('https://')) { + // Soundfont has a bug where you can't just pass it a URL + // @TODO: open an issue there + sfpromise = soundfont.instrument(this.context, instrument, { + isSoundfontUrl: () => true, + nameToUrl: () => instrument + }); + } + else if (instrument == 'percussion') { + sfpromise = soundfont.instrument(this.context, instrument, { soundfont: 'FluidR3_GM' }); + } + else { + sfpromise = soundfont.instrument(this.context, instrument); + } + promises.push(yield sfpromise.then(font => { + this.soundfonts.set(instrument, font); + })); + } + yield Promise.all(promises); + this.initialized = true; + }); + } + play(song) { + if (!this.style) { + throw new Error('No style selected'); + } + if (!this.initialized) { + throw new Error('A style hasn\'t finished loading'); + } + if (this.context.state == 'suspended') { + this.context.resume(); + } + let compiledSong = this.style.compile(song); + let tempoCoef = 0.4; // WHATEVER IDC HOW ANYTHING WORKS + let startTime = this.context.currentTime + 1; + for (let [instrument, notes] of compiledSong) { + let soundfont = this.soundfonts.get(instrument); + for (let note of notes) { + let start = startTime + (tempoCoef * note.time); + let dur = tempoCoef * note.duration - 0.05; + soundfont.play(note.midi, start, { + duration: dur, + gain: note.volume + }); + } + } + } +} + +export { PlaybackStyle, Player }; diff --git a/package-lock.json b/package-lock.json index c22c7e1..372ec7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6626 +4,1329 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "dev": true, "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" + "@babel/highlight": "^7.0.0" } }, - "@nodelib/fs.stat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz", - "integrity": "sha512-LAQ1d4OPfSJ/BMbI2DuizmYrrkD9JMaTdi2hQTlI53lQ4kRQPyZQRS4CYQ7O66bnBBnP/oYdRxbk++X0xuFU6A==", - "dev": true - }, - "@samverschueren/stream-to-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", - "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { - "any-observable": "^0.3.0" + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + } } }, - "@sindresorhus/is": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", - "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "@types/chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-zw8UvoBEImn392tLjxoavuonblX/4Yb9ha4KBU10FirCfwgzhKO0dvyJSF9ByxV1xK1r2AgnAi/tvQaLgxQqxA==", + "dev": true + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true, + "optional": true + }, + "@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "@types/node": { + "version": "12.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz", + "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==", "dev": true }, - "@webassemblyjs/ast": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.5.9.tgz", - "integrity": "sha512-xL3hC0TOc4ic1UNG8ZZNeaiPf1klozt6rqajcy7hfO/qqfkEhLff1AFt5g2LJkTjhw+QSEYVMt7qOaaApu7JzA==", + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", "dev": true, "requires": { - "@webassemblyjs/helper-module-context": "1.5.9", - "@webassemblyjs/helper-wasm-bytecode": "1.5.9", - "@webassemblyjs/wast-parser": "1.5.9", - "debug": "^3.1.0", - "mamacro": "^0.0.3" + "@types/node": "*" } }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.9.tgz", - "integrity": "sha512-naMJjuBqDqx4dPSzwpI9pkjdLds4tDTzvsOEzwxPDp655IfgLLP/QEvK/9PQp4p5DExqrR87rk8DWByoqWWlGA==", + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", "dev": true }, - "@webassemblyjs/helper-api-error": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.9.tgz", - "integrity": "sha512-tzGdqBo7Xf3McJcXbwbwzwElRzF/nELJN+G4MGGfm0DGRQB6UTmMe44jFIOQYT1Za89Aiz5DMQJotdnnLheixw==", + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "@webassemblyjs/helper-buffer": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.9.tgz", - "integrity": "sha512-WYkys6y33viEY23tHJ+KkSd9yHZBd54Sy6gcSgwLGPP1or9pLqWBrjWWATHuDuIkpvSJSt/+3qjAV6zHd1nS0g==", + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "debug": "^3.1.0" + "color-convert": "^1.9.0" } }, - "@webassemblyjs/helper-code-frame": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.9.tgz", - "integrity": "sha512-SYjNAlqcRH+YynslbIhFYOnGvE3WBl82/XlcFXiNkqnWsvHWnNkJbtxAtzrT/dcf69O/2pt8j1Q0+qc/rtacVw==", + "arg": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", + "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "@webassemblyjs/wast-printer": "1.5.9" + "sprintf-js": "~1.0.2" } }, - "@webassemblyjs/helper-fsm": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.9.tgz", - "integrity": "sha512-8D+VVIJTRbsn31zt3eyidYyUkhH1jk2/58mrIPiMarflRsisItJa5WZVu/gw0l+ubFOJf9PivTJB6Kw/Kgxx3g==", + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "babylon": { + "version": "7.0.0-beta.19", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", + "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==", "dev": true }, - "@webassemblyjs/helper-module-context": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.9.tgz", - "integrity": "sha512-DbeLbFOhioEeY7yAff12+n5sf7WP7Fmi0lnhCSzfW4xBsgwXKmRjAx7nVmsUf3z+BDnwHHVKIXBUM+ucccNUsw==", + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.9.tgz", - "integrity": "sha512-zHQuTMMd2nTyEa3fbmGfzlJW305py1sgf1gHNCO/LVN8nWlKysB/+6J68sP1Cd+9USnT1VS2vyD1z+YJPS6GqQ==", + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", "dev": true }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.9.tgz", - "integrity": "sha512-+ff+8Ju6sLCMFNygcDdLRNRsmuD0PHwq77d2mbfWj5YzUvFaKN2q2kRppJSEAixOnM2xLADuG5y/blpMo5G90A==", + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.9", - "@webassemblyjs/helper-buffer": "1.5.9", - "@webassemblyjs/helper-wasm-bytecode": "1.5.9", - "@webassemblyjs/wasm-gen": "1.5.9", - "debug": "^3.1.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "@webassemblyjs/ieee754": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.5.9.tgz", - "integrity": "sha512-mhetZBDnpV3VYqZb5Aail9X01VyIqDDZrNYdYj8bfx/PsVPG2znX90wRyVNTeqC5ylqHCgGkJ63bPaPEyINfsw==", + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", + "dev": true + }, + "catharsis": { + "version": "0.8.9", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", + "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=", "dev": true, "requires": { - "ieee754": "^1.1.11" + "underscore-contrib": "~0.3.0" } }, - "@webassemblyjs/leb128": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.5.9.tgz", - "integrity": "sha512-oZ3eUB9EViUtiuMwW/xeYamXgfFS2cmXl6aUIYBfpXJQ5v5aOC8ZuPpz2/LqlgNlT8ThpyFd6kfgkYVwKwkGvQ==", + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", "dev": true, "requires": { - "leb": "^0.3.0" + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" } }, - "@webassemblyjs/wasm-edit": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.9.tgz", - "integrity": "sha512-pMWe3HomnWAMZytJ5sSNBS6qTbSoULUHkvDrtcarmLBTclmupZe25INy1jxbWGKsuFxw6w0xQ+eLRPlC8HPjhg==", + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.9", - "@webassemblyjs/helper-buffer": "1.5.9", - "@webassemblyjs/helper-wasm-bytecode": "1.5.9", - "@webassemblyjs/helper-wasm-section": "1.5.9", - "@webassemblyjs/wasm-gen": "1.5.9", - "@webassemblyjs/wasm-opt": "1.5.9", - "@webassemblyjs/wasm-parser": "1.5.9", - "@webassemblyjs/wast-printer": "1.5.9", - "debug": "^3.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "@webassemblyjs/wasm-gen": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.9.tgz", - "integrity": "sha512-UEhymlxupBUJuwnD2N860MqkpE7LHt0tNKqAgT4YAVjbx+88P6MBBk+q+9wr2FJCXxMgsPTxMWifqC4wd2FzVg==", + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.9", - "@webassemblyjs/helper-wasm-bytecode": "1.5.9", - "@webassemblyjs/ieee754": "1.5.9", - "@webassemblyjs/leb128": "1.5.9" + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" } }, - "@webassemblyjs/wasm-opt": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.9.tgz", - "integrity": "sha512-oQm84US3e36dPq5bOeybVKA2ZyzeWR4fereg9kJa0Y9XLKxHwlsBa2kFyNXwZNrhMP33iyXAW+ym7om1zPZeAg==", + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.9", - "@webassemblyjs/helper-buffer": "1.5.9", - "@webassemblyjs/wasm-gen": "1.5.9", - "@webassemblyjs/wasm-parser": "1.5.9", - "debug": "^3.1.0" + "color-name": "^1.1.1" } }, - "@webassemblyjs/wasm-parser": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.9.tgz", - "integrity": "sha512-jBKBTKE4M/WYCSqLjRvK+/QD55E/HNcQjswbksof3GEXfkq0iMqYxoPfqR7uLAD9/jVf9HpBNW2FJOyfTTlYfw==", + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.9", - "@webassemblyjs/helper-api-error": "1.5.9", - "@webassemblyjs/helper-wasm-bytecode": "1.5.9", - "@webassemblyjs/ieee754": "1.5.9", - "@webassemblyjs/leb128": "1.5.9", - "@webassemblyjs/wasm-parser": "1.5.9" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, - "@webassemblyjs/wast-parser": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.5.9.tgz", - "integrity": "sha512-bDuYH/NR5D+MmwVZdGW2rUvu4UcKGpodiHBSueajon3oNPu+PAKG+7br3BVFKxDUtDoVtuHLUQvkqp1lTrqPCA==", + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.9", - "@webassemblyjs/floating-point-hex-parser": "1.5.9", - "@webassemblyjs/helper-api-error": "1.5.9", - "@webassemblyjs/helper-code-frame": "1.5.9", - "@webassemblyjs/helper-fsm": "1.5.9", - "long": "^3.2.0", - "mamacro": "^0.0.3" + "type-detect": "^4.0.0" } }, - "@webassemblyjs/wast-printer": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.5.9.tgz", - "integrity": "sha512-04iV32TO69kZChP3DN6W8i6GCa5UtEn1Lnzb4sQGe5YNjIFz2k8+KZLxbovWIZgj9pk06k3Egq/wyD98lSKaLw==", + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.5.9", - "@webassemblyjs/wast-parser": "1.5.9", - "long": "^3.2.0" + "object-keys": "^1.0.12" } }, - "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "acorn-dynamic-import": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", - "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "acorn": "^5.0.0" + "once": "^1.4.0" } }, - "ajv": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.0.tgz", - "integrity": "sha512-VDUX1oSajablmiyFyED9L1DFndg0P9h7p1F+NO8FkIzei6EPrR6Zu1n18rd5P8PqaSRd/FrWv3G1TVBqpM83gA==", + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0", - "uri-js": "^4.2.1" + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" } }, - "ajv-keywords": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", - "dev": true + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } }, - "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", "dev": true }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true }, - "any-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", - "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", "dev": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "is-buffer": "~2.0.3" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true + } } }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "array-uniq": "^1.0.1" + "function-bind": "^1.1.1" } }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "util": "0.10.3" + "once": "^1.3.0", + "wrappy": "1" } }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "ast-types": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.3.tgz", - "integrity": "sha512-XA5o5dsNw8MhyW0Q7MWXJWc4oOzZKbdsEJq45h7c8q/d9DwWZ5F2ugUc1PuMLPGsUnphCt/cNDHu8JeBbxf1qA==", + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", "dev": true }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "atob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", "dev": true }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - }, - "dependencies": { - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "dev": true, - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - }, - "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true - } - } - }, - "babel-helper-bindify-decorators": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz", - "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", - "dev": true, - "requires": { - "babel-helper-explode-assignable-expression": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "dev": true, - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "dev": true, - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-explode-class": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz", - "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=", - "dev": true, - "requires": { - "babel-helper-bindify-decorators": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "dev": true, - "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", - "dev": true, - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "dev": true, - "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", - "dev": true - }, - "babel-plugin-syntax-async-generators": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", - "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=", - "dev": true - }, - "babel-plugin-syntax-class-constructor-call": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz", - "integrity": "sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY=", - "dev": true - }, - "babel-plugin-syntax-class-properties": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", - "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", - "dev": true - }, - "babel-plugin-syntax-decorators": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", - "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", - "dev": true - }, - "babel-plugin-syntax-dynamic-import": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", - "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=", - "dev": true - }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", - "dev": true - }, - "babel-plugin-syntax-export-extensions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz", - "integrity": "sha1-cKFITw+QiaToStRLrDU8lbmxJyE=", - "dev": true - }, - "babel-plugin-syntax-flow": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", - "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=", - "dev": true - }, - "babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", - "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", - "dev": true - }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", - "dev": true - }, - "babel-plugin-transform-async-generator-functions": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz", - "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=", - "dev": true, - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-generators": "^6.5.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "dev": true, - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-functions": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-class-constructor-call": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz", - "integrity": "sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk=", - "dev": true, - "requires": { - "babel-plugin-syntax-class-constructor-call": "^6.18.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-class-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", - "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", - "dev": true, - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-plugin-syntax-class-properties": "^6.8.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-decorators": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz", - "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=", - "dev": true, - "requires": { - "babel-helper-explode-class": "^6.24.1", - "babel-plugin-syntax-decorators": "^6.13.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "dev": true, - "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "dev": true, - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "dev": true, - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", - "dev": true, - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "dev": true, - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "dev": true, - "requires": { - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", - "dev": true, - "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "dev": true, - "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", - "dev": true, - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "dev": true, - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "regexpu-core": "^2.0.0" - } - }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", - "dev": true, - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", - "babel-plugin-syntax-exponentiation-operator": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-export-extensions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz", - "integrity": "sha1-U3OLR+deghhYnuqUbLvTkQm75lM=", - "dev": true, - "requires": { - "babel-plugin-syntax-export-extensions": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-flow-strip-types": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", - "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", - "dev": true, - "requires": { - "babel-plugin-syntax-flow": "^6.18.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-object-rest-spread": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", - "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", - "dev": true, - "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" - } - }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", - "dev": true, - "requires": { - "regenerator-transform": "^0.10.0" - } - }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-preset-es2015": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", - "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", - "dev": true, - "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.24.1", - "babel-plugin-transform-es2015-classes": "^6.24.1", - "babel-plugin-transform-es2015-computed-properties": "^6.24.1", - "babel-plugin-transform-es2015-destructuring": "^6.22.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1", - "babel-plugin-transform-es2015-for-of": "^6.22.0", - "babel-plugin-transform-es2015-function-name": "^6.24.1", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-umd": "^6.24.1", - "babel-plugin-transform-es2015-object-super": "^6.24.1", - "babel-plugin-transform-es2015-parameters": "^6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.24.1", - "babel-plugin-transform-regenerator": "^6.24.1" - } - }, - "babel-preset-stage-1": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz", - "integrity": "sha1-dpLNfc1oSZB+auSgqFWJz7niv7A=", - "dev": true, - "requires": { - "babel-plugin-transform-class-constructor-call": "^6.24.1", - "babel-plugin-transform-export-extensions": "^6.22.0", - "babel-preset-stage-2": "^6.24.1" - } - }, - "babel-preset-stage-2": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz", - "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=", - "dev": true, - "requires": { - "babel-plugin-syntax-dynamic-import": "^6.18.0", - "babel-plugin-transform-class-properties": "^6.24.1", - "babel-plugin-transform-decorators": "^6.24.1", - "babel-preset-stage-3": "^6.24.1" - } - }, - "babel-preset-stage-3": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz", - "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=", - "dev": true, - "requires": { - "babel-plugin-syntax-trailing-function-commas": "^6.22.0", - "babel-plugin-transform-async-generator-functions": "^6.24.1", - "babel-plugin-transform-async-to-generator": "^6.24.1", - "babel-plugin-transform-exponentiation-operator": "^6.24.1", - "babel-plugin-transform-object-rest-spread": "^6.22.0" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - }, - "dependencies": { - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - } - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "dependencies": { - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "7.0.0-beta.19", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", - "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", - "dev": true - }, - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "dev": true - }, - "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", - "dev": true - }, - "binaryextensions": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz", - "integrity": "sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==", - "dev": true - }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", - "dev": true - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.1.tgz", - "integrity": "sha512-zy0Cobe3hhgpiOM32Tj7KQ3Vl91m0njwsjzZQK1L+JDf11dzP9qIvjreVinsvXrgfjhStXwUWAEpB9D7Gwmayw==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "dev": true, - "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, - "requires": { - "pako": "~1.0.5" - } - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", - "dev": true - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, - "cacache": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", - "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", - "dev": true, - "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.1", - "mississippi": "^2.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", - "ssri": "^5.2.4", - "unique-filename": "^1.1.0", - "y18n": "^4.0.0" - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cacheable-request": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", - "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", - "dev": true, - "requires": { - "clone-response": "1.0.2", - "get-stream": "3.0.0", - "http-cache-semantics": "3.8.1", - "keyv": "3.0.0", - "lowercase-keys": "1.0.0", - "normalize-url": "2.0.1", - "responselike": "1.0.2" - }, - "dependencies": { - "lowercase-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", - "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", - "dev": true - } - } - }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "catharsis": { - "version": "0.8.9", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", - "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=", - "dev": true, - "requires": { - "underscore-contrib": "~0.3.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true - }, - "chokidar": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz", - "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.1.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.0" - } - }, - "chownr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", - "dev": true - }, - "chrome-trace-event": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-0.1.3.tgz", - "integrity": "sha512-sjndyZHrrWiu4RY7AkHgjn80GfAM2ZSzUkZLV/Js59Ldmh6JDThf0SUmOHU53rFu2rVxxfCzJ30Ukcfch3Gb/A==", - "dev": true - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-spinners": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz", - "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=", - "dev": true - }, - "cli-table": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", - "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", - "dev": true, - "requires": { - "colors": "1.0.3" - }, - "dependencies": { - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true - } - } - }, - "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", - "dev": true, - "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", - "dev": true - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "cloneable-readable": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", - "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, - "requires": { - "color-name": "^1.1.1" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "^0.1.4" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", - "dev": true - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", - "dev": true - }, - "dargs": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz", - "integrity": "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk=", - "dev": true - }, - "date-fns": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", - "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==", - "dev": true - }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, - "dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-extend": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", - "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", - "dev": true - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "detect-conflict": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.1.tgz", - "integrity": "sha1-CIZXpmqWHAUBnbfEIwiDsca0F24=", - "dev": true - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "dir-glob": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "path-type": "^3.0.0" - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "duplexify": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "editions": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", - "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", - "dev": true - }, - "ejs": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", - "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==", - "dev": true - }, - "elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", - "dev": true - }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz", - "integrity": "sha512-jox/62b2GofV1qTUQTMPEJSDIGycS43evqYzD/KVtEb9OCoki9cnacUPxCrZa7JfPzZSYOCZhu9O9luaMxAX8g==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" - } - }, - "envinfo": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-5.9.0.tgz", - "integrity": "sha512-JeaiKfpCYQwIgSupqfApjt+AMMc1iffwHDr4YqnO8JBlbirgeAE3nZui8aSVsEUij25oG0Pi20MQZwins5shPQ==", - "dev": true - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "error": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", - "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", - "dev": true, - "requires": { - "string-template": "~0.2.1", - "xtend": "~4.0.0" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", - "dev": true - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "dev": true - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - } - } - }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "requires": { - "fill-range": "^2.1.0" - }, - "dependencies": { - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "fast-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.2.tgz", - "integrity": "sha512-TR6zxCKftDQnUAPvkrCWdBgDq/gbqx8A3ApnBrR5rMvpp6+KMJI0Igw7fkWPgeVK0uhRXTXdvO3O+YP0CaUX2g==", - "dev": true, - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.0.1", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.1", - "micromatch": "^3.1.10" - } - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "first-chunk-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", - "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "flow-parser": { - "version": "0.73.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.73.0.tgz", - "integrity": "sha512-9JB+2hrKJ+S1OZ+upIwNTGlaLDRga2iC9KvpqWVFEVNlCxc51pkhNJRmA0PmUcLcEtFAW6IGBmVi70r+j+Qp9A==", - "dev": true - }, - "flush-write-stream": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", - "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.21", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": "^2.1.0" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "minipass": { - "version": "2.2.4", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.2.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.10.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.1.10", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.1.1", - "bundled": true, - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.5.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "yallist": { - "version": "3.0.2", - "bundled": true, - "dev": true - } - } - }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "gh-got": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-6.0.0.tgz", - "integrity": "sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw==", - "dev": true, - "requires": { - "got": "^7.0.0", - "is-plain-obj": "^1.1.0" - }, - "dependencies": { - "got": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", - "dev": true, - "requires": { - "decompress-response": "^3.2.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-plain-obj": "^1.1.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "p-cancelable": "^0.3.0", - "p-timeout": "^1.1.1", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "url-parse-lax": "^1.0.0", - "url-to-options": "^1.0.1" - } - }, - "p-cancelable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", - "dev": true - }, - "p-timeout": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", - "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", - "dev": true, - "requires": { - "p-finally": "^1.0.0" - } - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - } - } - }, - "github-username": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/github-username/-/github-username-4.1.0.tgz", - "integrity": "sha1-y+KABBiDIG2kISrp5LXxacML9Bc=", - "dev": true, - "requires": { - "gh-got": "^6.0.0" - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-all": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.1.0.tgz", - "integrity": "sha1-iRPd+17hrHgSZWJBsD1SF8ZLAqs=", - "dev": true, - "requires": { - "glob": "^7.0.5", - "yargs": "~1.2.6" - }, - "dependencies": { - "minimist": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.1.0.tgz", - "integrity": "sha1-md9lelJXTCHJBXSX33QnkLK0wN4=", - "dev": true - }, - "yargs": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.2.6.tgz", - "integrity": "sha1-nHtKgv1dWVsr8Xq23MQxNUMv40s=", - "dev": true, - "requires": { - "minimist": "^0.1.0" - } - } - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "globby": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", - "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - } - }, - "got": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/got/-/got-8.3.1.tgz", - "integrity": "sha512-tiLX+bnYm5A56T5N/n9Xo89vMaO1mrS9qoDqj3u/anVooqGozvY/HbXzEpDfbNeKsHCBpK40gSbz8wGYSp3i1w==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.7.0", - "cacheable-request": "^2.1.1", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "into-stream": "^3.1.0", - "is-retry-allowed": "^1.1.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "mimic-response": "^1.0.0", - "p-cancelable": "^0.4.0", - "p-timeout": "^2.0.1", - "pify": "^3.0.0", - "safe-buffer": "^5.1.1", - "timed-out": "^4.0.1", - "url-parse-lax": "^3.0.0", - "url-to-options": "^1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, - "grouped-queue": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.3.tgz", - "integrity": "sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=", - "dev": true, - "requires": { - "lodash": "^4.17.2" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - } - } - }, - "has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbol-support-x": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", - "dev": true - }, - "has-to-string-tag-x": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", - "dev": true, - "requires": { - "has-symbol-support-x": "^1.4.1" - } - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hosted-git-info": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", - "dev": true - }, - "http-cache-semantics": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", - "dev": true - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", - "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==", - "dev": true - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, - "ignore": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.8.tgz", - "integrity": "sha512-pUh+xUQQhQzevjRHHFqqcTy0/dP/kS9I8HSrUydhihjuD09W6ldVWFtIrwhXdUJHis3i2rZNqEHpZH/cbinFbg==", - "dev": true - }, - "import-local": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", - "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", - "dev": true, - "requires": { - "pkg-dir": "^2.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true - }, - "inquirer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", - "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.1.0", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^5.5.2", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", - "dev": true - }, - "into-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", - "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", - "dev": true, - "requires": { - "from2": "^2.1.1", - "p-is-promise": "^1.1.0" - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", - "dev": true - }, - "is-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", - "dev": true, - "requires": { - "symbol-observable": "^1.1.0" - }, - "dependencies": { - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true - } - } - }, - "is-odd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", - "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-retry-allowed": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", - "dev": true - }, - "is-scoped": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-1.0.0.tgz", - "integrity": "sha1-RJypgpnnEwOCViieyytUDcQ3yzA=", - "dev": true, - "requires": { - "scoped-regex": "^1.0.0" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isbinaryfile": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", - "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "istextorbinary": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz", - "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", - "dev": true, - "requires": { - "binaryextensions": "2", - "editions": "^1.3.3", - "textextensions": "2" - } - }, - "isurl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", - "dev": true, - "requires": { - "has-to-string-tag-x": "^1.2.0", - "is-object": "^1.0.1" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "js2xmlparser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", - "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", - "dev": true, - "requires": { - "xmlcreate": "^1.0.1" - } - }, - "jscodeshift": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.5.0.tgz", - "integrity": "sha512-JAcQINNMFpdzzpKJN8k5xXjF3XDuckB1/48uScSzcnNyK199iWEc9AxKL9OoX5144M2w5zEx9Qs4/E/eBZZUlw==", - "dev": true, - "requires": { - "babel-plugin-transform-flow-strip-types": "^6.8.0", - "babel-preset-es2015": "^6.9.0", - "babel-preset-stage-1": "^6.5.0", - "babel-register": "^6.9.0", - "babylon": "^7.0.0-beta.30", - "colors": "^1.1.2", - "flow-parser": "^0.*", - "lodash": "^4.13.1", - "micromatch": "^2.3.7", - "neo-async": "^2.5.0", - "node-dir": "0.1.8", - "nomnom": "^1.8.1", - "recast": "^0.14.1", - "temp": "^0.8.1", - "write-file-atomic": "^1.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", - "dev": true - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "babylon": { - "version": "7.0.0-beta.47", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.47.tgz", - "integrity": "sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==", - "dev": true - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", - "dev": true, - "requires": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" - } - }, - "colors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.0.tgz", - "integrity": "sha512-EDpX3a7wHMWFA7PUHWPHNWqOxIIRSJetuwl0AS5Oi/5FMV8kWm69RTlgm00GKjBO1xFHMtBbL49yRtMMdticBw==", - "dev": true - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "nomnom": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", - "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", - "dev": true, - "requires": { - "chalk": "~0.4.0", - "underscore": "~1.6.0" - } - }, - "strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", - "dev": true - }, - "underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", - "dev": true - } - } - }, - "jsdoc": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", - "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", - "dev": true, - "requires": { - "babylon": "7.0.0-beta.19", - "bluebird": "~3.5.0", - "catharsis": "~0.8.9", - "escape-string-regexp": "~1.0.5", - "js2xmlparser": "~3.0.0", - "klaw": "~2.0.0", - "marked": "~0.3.6", - "mkdirp": "~0.5.1", - "requizzle": "~0.2.1", - "strip-json-comments": "~2.0.1", - "taffydb": "2.6.2", - "underscore": "~1.8.3" - }, - "dependencies": { - "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", - "dev": true - } - } - }, - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, - "keyv": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", - "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "klaw": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", - "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, - "leb": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/leb/-/leb-0.3.0.tgz", - "integrity": "sha1-Mr7p+tFoMo1q6oUi2DP0GA7tHaM=", - "dev": true - }, - "listr": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.1.tgz", - "integrity": "sha512-MSMUUVN1f8aRnPi4034RkOqdiUlpYW+FqwFE3aL0uYNPRavkt2S2SsSpDDofn8BDpqv2RNnsdOcCHWsChcq77A==", - "dev": true, - "requires": { - "@samverschueren/stream-to-observable": "^0.3.0", - "cli-truncate": "^0.2.1", - "figures": "^1.7.0", - "indent-string": "^2.1.0", - "is-observable": "^1.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.4.0", - "listr-verbose-renderer": "^0.4.0", - "log-symbols": "^1.0.2", - "log-update": "^1.0.2", - "ora": "^0.2.3", - "p-map": "^1.1.1", - "rxjs": "^6.1.0", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - } - }, - "rxjs": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.0.tgz", - "integrity": "sha512-qBzf5uu6eOKiCZuAE0SgZ0/Qp+l54oeVxFfC2t+mJ2SFI6IB8gmMdJHs5DUMu5kqifqcCtsKS2XHjhZu6RKvAw==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", - "dev": true - }, - "listr-update-renderer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz", - "integrity": "sha1-NE2YDaLKLosUW6MFkI8yrj9MyKc=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^1.0.2", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "listr-verbose-renderer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", - "integrity": "sha1-ggb0z21S3cWCfl/RSYng6WWTOjU=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-cursor": "^1.0.2", - "date-fns": "^1.27.2", - "figures": "^1.7.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true, - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true, - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "loader-runner": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", - "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", - "dev": true - }, - "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "dev": true, - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", - "dev": true - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "log-update": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", - "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", - "dev": true, - "requires": { - "ansi-escapes": "^1.0.0", - "cli-cursor": "^1.0.2" - }, - "dependencies": { - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", - "dev": true - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true, - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true, - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - } - } - }, - "long": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", - "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=", - "dev": true - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "dev": true, - "requires": { - "js-tokens": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, - "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "mamacro": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", - "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", - "dev": true - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "marked": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", - "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", - "dev": true - }, - "math-random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", - "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", - "dev": true - }, - "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "mem-fs": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.3.tgz", - "integrity": "sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=", - "dev": true, - "requires": { - "through2": "^2.0.0", - "vinyl": "^1.1.0", - "vinyl-file": "^2.0.0" - } - }, - "mem-fs-editor": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-4.0.2.tgz", - "integrity": "sha512-QHvdXLLNmwJXxKdf7x27aNUren6IoPxwcM8Sfd+S6/ddQQMcYdEtVKsh6ilpqMrU18VQuKZEaH0aCGt3JDbA0g==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "deep-extend": "^0.5.1", - "ejs": "^2.5.9", - "glob": "^7.0.3", - "globby": "^8.0.0", - "isbinaryfile": "^3.0.2", - "mkdirp": "^0.5.0", - "multimatch": "^2.0.0", - "rimraf": "^2.2.8", - "through2": "^2.0.0", - "vinyl": "^2.0.1" - }, - "dependencies": { - "clone": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", - "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", - "dev": true - }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", - "dev": true - }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", - "dev": true - }, - "vinyl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", - "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", - "dev": true, - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - } - } - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "merge2": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.2.tgz", - "integrity": "sha512-bgM8twH86rWni21thii6WCMQMRMmwqqdW3sGWi9IipnVAszdLXRjwDwAnyrVXo6DuP3AjRMMttZKUB48QWIFGg==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "mimic-response": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz", - "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mississippi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", - "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", - "dev": true, - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^2.0.1", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "multimatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", - "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", - "dev": true, - "requires": { - "array-differ": "^1.0.0", - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "minimatch": "^3.0.0" - } - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", - "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "neo-async": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz", - "integrity": "sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA==", - "dev": true - }, - "nice-try": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", - "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", - "dev": true - }, - "node-dir": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.8.tgz", - "integrity": "sha1-VfuN62mQcHB/tn+RpGDwRIKUx30=", - "dev": true - }, - "node-libs-browser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", - "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", - "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^1.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.0", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.10.3", - "vm-browserify": "0.0.4" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "normalize-url": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", - "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", - "dev": true, - "requires": { - "prepend-http": "^2.0.0", - "query-string": "^5.0.1", - "sort-keys": "^2.0.0" - } - }, - "notochord-song": { - "version": "git+https://github.com/notochord/notochord-song.git#f5e6033ade867923d7226a061a1b8f8d1f733c3b", - "from": "git+https://github.com/notochord/notochord-song.git#0.1.2", - "requires": { - "tonal": "^2.2.2" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "on-build-webpack": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/on-build-webpack/-/on-build-webpack-0.1.0.tgz", - "integrity": "sha1-oofA4Xdm5hQZJuXyy7DYu1O3aBQ=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "ora": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", - "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", - "dev": true, - "requires": { - "chalk": "^1.1.1", - "cli-cursor": "^1.0.2", - "cli-spinners": "^0.1.2", - "object-assign": "^4.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true, - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true, - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-cancelable": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", - "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", - "dev": true - }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", - "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", - "dev": true - }, - "p-lazy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-lazy/-/p-lazy-1.0.0.tgz", - "integrity": "sha1-7FPIAvLuOsKPFmzILQsrAt4nqDU=", - "dev": true - }, - "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", - "dev": true - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true - }, - "p-timeout": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", - "dev": true, - "requires": { - "p-finally": "^1.0.0" + "has": "^1.0.1" } }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", - "dev": true - }, - "parallel-transform": { + "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", - "dev": true, - "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "parse-asn1": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", - "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", - "dev": true, - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" - } - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pbkdf2": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", - "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", - "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true - }, - "prettier": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.13.3.tgz", - "integrity": "sha512-CIWJNU+cFFdeA0GJSzzFkxiq2WuMvWZMlz6cV/EXhPlRnI3esSFMh+lNmyZ8z/X8O8C1U60Sc8puXALj4/WmZw==", - "dev": true - }, - "pretty-bytes": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz", - "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=", - "dev": true - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "public-encrypt": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", - "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, - "query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", "dev": true, "requires": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" + "has-symbols": "^1.0.0" } }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "randomatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", - "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", + "jest-worker": { + "version": "24.6.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.6.0.tgz", + "integrity": "sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ==", "dev": true, "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" + "merge-stream": "^1.0.1", + "supports-color": "^6.1.0" }, "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, - "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { - "safe-buffer": "^5.1.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", "dev": true, "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" + "xmlcreate": "^1.0.1" } }, - "read-chunk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", - "integrity": "sha1-agTAkoAF7Z1C4aasVgDhnLx/9lU=", + "jsdoc": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", + "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", "dev": true, "requires": { - "pify": "^3.0.0", - "safe-buffer": "^5.1.1" + "babylon": "7.0.0-beta.19", + "bluebird": "~3.5.0", + "catharsis": "~0.8.9", + "escape-string-regexp": "~1.0.5", + "js2xmlparser": "~3.0.0", + "klaw": "~2.0.0", + "marked": "~0.3.6", + "mkdirp": "~0.5.1", + "requizzle": "~0.2.1", + "strip-json-comments": "~2.0.1", + "taffydb": "2.6.2", + "underscore": "~1.8.3" + }, + "dependencies": { + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", + "dev": true + } } }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "dev": true, + "optional": true, "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true, + "optional": true + } } }, - "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "klaw": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", + "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "graceful-fs": "^4.1.9" } }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true }, - "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "readable-stream": "^2.0.2", - "set-immediate-shim": "^1.0.1" + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" } }, - "recast": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.14.7.tgz", - "integrity": "sha512-/nwm9pkrcWagN40JeJhkPaRxiHXBRkXyRh/hgU088Z/v+qCy+zIHHY6bC6o7NaKAxPqtE6nD8zBH1LfU0/Wx6A==", + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", "dev": true, "requires": { - "ast-types": "0.11.3", - "esprima": "~4.0.0", - "private": "~0.1.5", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } + "lodash._reinterpolate": "^3.0.0" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "dev": true, "requires": { - "resolve": "^1.1.6" + "chalk": "^2.0.1" } }, - "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", "dev": true }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "dev": true, "requires": { - "babel-runtime": "^6.18.0", - "babel-types": "^6.19.0", - "private": "^0.1.6" + "p-defer": "^1.0.0" } }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" - } + "marked": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", + "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", + "dev": true }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "readable-stream": "^2.0.1" } }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" + "brace-expansion": "^1.1.7" } }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { - "jsesc": "~0.5.0" + "minimist": "0.0.8" } }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" + "mocha": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz", + "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.2.2", + "yargs-parser": "13.0.0", + "yargs-unparser": "1.5.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", + "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.0.0" + } + }, + "yargs-parser": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", + "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } } }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "nice-try": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", + "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", "dev": true }, - "requizzle": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", - "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", + "node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", "dev": true, "requires": { - "underscore": "~1.6.0" + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" }, "dependencies": { - "underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true } } }, - "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", - "dev": true, + "notochord-song": { + "version": "git+https://github.com/notochord/notochord-song.git#6ffdbbf480ea4de604019e14f80bbe15e368989d", + "from": "git+https://github.com/notochord/notochord-song.git#1.1.0", "requires": { - "path-parse": "^1.0.5" + "tonal": "^2.2.2" } }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "resolve-from": "^3.0.0" + "path-key": "^2.0.0" } }, - "resolve-dir": { + "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "^7.0.5" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { - "aproba": "^1.1.1" + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" } }, - "rxjs": { - "version": "5.5.11", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.11.tgz", - "integrity": "sha512-3bjO7UwWfA2CV7lmwYMBzj4fQ6Cq+ftHc2MvUe+WMS7wcdJ1LosDWmdjPQanYp2dBRj572p7PeU81JUxHKOcBA==", + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", "dev": true, "requires": { - "symbol-observable": "1.0.1" + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "ret": "~0.1.10" + "wrappy": "1" } }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, - "schema-utils": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", - "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - } - }, - "scoped-regex": { + "p-finally": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz", - "integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, - "serialize-javascript": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", - "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==", + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, - "set-value": { + "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, - "shelljs": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz", - "integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==", + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requizzle": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", + "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", "dev": true, "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "underscore": "~1.6.0" }, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true } } }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "rollup": { + "version": "1.19.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.19.4.tgz", + "integrity": "sha512-G24w409GNj7i/Yam2cQla6qV2k6Nug8bD2DZg9v63QX/cH/dEdbNJg8H4lUm5M1bRpPKRUC465Rm9H51JTKOfQ==", "dev": true, "requires": { - "kind-of": "^3.2.0" + "@types/estree": "0.0.39", + "@types/node": "^12.6.9", + "acorn": "^6.2.1" }, "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "source-list-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "dev": true, - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" + "acorn": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", + "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==", + "dev": true + } } }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "rollup-plugin-alias": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-alias/-/rollup-plugin-alias-1.5.2.tgz", + "integrity": "sha512-ODeZXhTxpD48sfcYLAFc1BGrsXKDj7o1CSNH3uYbdK3o0NxyMmaQPTNgW+ko+am92DLC8QSTe4kyxTuEkI5S5w==", "dev": true, "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } } }, - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "rollup-plugin-banner": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-banner/-/rollup-plugin-banner-0.2.1.tgz", + "integrity": "sha512-Bs1uIPCsGpKIkNOwmBsCqn+dJ/xaojWk9PNlvd+1MEScddr1yUQlO6McAXi72wJyNWYL+9u9EI2JAZMpLRH92w==", "dev": true, "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "lodash.template": "^4.4.0" } }, - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "rollup-plugin-node-resolve": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", + "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.11.1", + "rollup-pluginutils": "^2.8.1" + }, + "dependencies": { + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } } }, - "ssri": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", - "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "rollup-plugin-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.1.1.tgz", + "integrity": "sha512-McIMCDEY8EU6Y839C09UopeRR56wXHGdvKKjlfiZG/GrP6wvZQ62u2ko/Xh1MNH2M9WDL+obAAHySljIZYCuPQ==", "dev": true, "requires": { - "safe-buffer": "^5.1.1" + "@babel/code-frame": "^7.0.0", + "jest-worker": "^24.6.0", + "rollup-pluginutils": "^2.8.1", + "serialize-javascript": "^1.7.0", + "terser": "^4.1.0" + }, + "dependencies": { + "serialize-javascript": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz", + "integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==", + "dev": true + } } }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "rollup-plugin-typescript": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-typescript/-/rollup-plugin-typescript-1.0.1.tgz", + "integrity": "sha512-rwJDNn9jv/NsKZuyBb/h0jsclP4CJ58qbvZt2Q9zDIGILF2LtdtvCqMOL+Gq9IVq5MTrTlHZNrn8h7VjQgd8tw==", "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "resolve": "^1.10.0", + "rollup-pluginutils": "^2.5.0" }, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "path-parse": "^1.0.6" } } } }, - "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "rollup-pluginutils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz", + "integrity": "sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==", "dev": true, "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" + "estree-walker": "^0.6.1" } }, - "stream-each": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", - "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true }, - "stream-http": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.2.tgz", - "integrity": "sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==", + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" + "shebang-regex": "^1.0.0" } }, - "stream-shift": { + "shebang-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, - "string-template": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, "string-width": { @@ -6655,23 +1358,11 @@ } }, "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, - "strip-bom-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", - "integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true, - "requires": { - "first-chunk-stream": "^2.0.0", - "strip-bom": "^2.0.0" - } + "optional": true }, "strip-eof": { "version": "1.0.0", @@ -6694,148 +1385,47 @@ "has-flag": "^3.0.0" } }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", - "dev": true - }, "taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", "dev": true }, - "tapable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz", - "integrity": "sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg==", - "dev": true - }, - "temp": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", - "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", + "terser": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.1.4.tgz", + "integrity": "sha512-+ZwXJvdSwbd60jG0Illav0F06GDJF0R4ydZ21Q3wGAFKoBGyJGo34F63vzJHgvYxc1ukOtIjvwEvl9MkjzM6Pg==", "dev": true, "requires": { - "os-tmpdir": "^1.0.0", - "rimraf": "~2.2.6" + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" }, "dependencies": { - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "textextensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz", - "integrity": "sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA==", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true - }, - "timers-browserify": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", - "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } } } }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, "tonal": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/tonal/-/tonal-2.2.2.tgz", @@ -6938,566 +1528,116 @@ "tonal-pcset": "^2.2.2" } }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, - "tslib": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.2.tgz", - "integrity": "sha512-AVP5Xol3WivEr7hnssHDsaM+lVrVXWUvd1cfXTRkTj80b//6g2wIFEH6hZG0muGZRnHGrfttpdzRk3YlBkWjKw==", - "dev": true - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", - "dev": true, - "requires": { - "commander": "~2.13.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "uglifyjs-webpack-plugin": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz", - "integrity": "sha512-hIQJ1yxAPhEA2yW/i7Fr+SXZVMp+VEI3d42RTHBgQd2yhp/1UdBcR3QEWPV5ahBxlqQDMEMTuTEvDHSFINfwSw==", - "dev": true, - "requires": { - "cacache": "^10.0.4", - "find-cache-dir": "^1.0.0", - "schema-utils": "^0.4.5", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "uglify-es": "^3.3.4", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "underscore-contrib": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", - "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", - "dev": true, - "requires": { - "underscore": "1.6.0" - }, - "dependencies": { - "underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", - "dev": true - } - } - }, - "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } - } - }, - "unique-filename": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", - "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", - "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "untildify": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", - "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", - "dev": true - }, - "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", - "dev": true - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "ts-mocha": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-7.0.0.tgz", + "integrity": "sha512-7WfkQw1W6JZXG5m4E1w2e945uWzBoZqmnOHvpMu0v+zvyKLdUQeTtRMfcQsVEKsUnYL6nTyH4okRt2PZucmFXQ==", "dev": true, "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" + "ts-node": "7.0.1", + "tsconfig-paths": "^3.5.0" }, "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + } + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", "dev": true } } }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - } - }, - "url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", - "dev": true - }, - "use": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "ts-node": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", + "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", "dev": true, "requires": { - "inherits": "2.0.1" + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" }, "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", "dev": true } } }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "v8-compile-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.0.tgz", - "integrity": "sha512-qNdTUMaCjPs4eEnM3W9H94R3sU70YCuT+/ST7nUf+id1bVOrdjrpUaeZLqPBPRph3hsgn4a4BvwpxhHZx+oSDg==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "vinyl-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-2.0.0.tgz", - "integrity": "sha1-p+v1/779obfRjRQPyweyI++2dRo=", + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", "dev": true, + "optional": true, "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.3.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0", - "strip-bom-stream": "^2.0.0", - "vinyl": "^1.1.0" + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" }, "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true, + "optional": true } } }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true }, - "watchpack": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", - "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", - "dev": true, - "requires": { - "chokidar": "^2.0.2", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" - } + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true }, - "webpack": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.10.2.tgz", - "integrity": "sha512-S4yIBevM7DFSAOAvWSBgvuH5mtJ3HgjAS6tCGsTxxHtrVdbntdRVaPey2u9sCns6KV859Vwd2DwkvBLTcs6t6g==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.5.9", - "@webassemblyjs/wasm-edit": "1.5.9", - "@webassemblyjs/wasm-opt": "1.5.9", - "@webassemblyjs/wasm-parser": "1.5.9", - "acorn": "^5.0.0", - "acorn-dynamic-import": "^3.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^0.1.1", - "enhanced-resolve": "^4.0.0", - "eslint-scope": "^3.7.1", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^0.4.4", - "tapable": "^1.0.0", - "uglifyjs-webpack-plugin": "^1.2.4", - "watchpack": "^1.5.0", - "webpack-sources": "^1.0.1" - } + "typescript": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", + "dev": true }, - "webpack-addons": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/webpack-addons/-/webpack-addons-1.1.5.tgz", - "integrity": "sha512-MGO0nVniCLFAQz1qv22zM02QPjcpAoJdy7ED0i3Zy7SY1IecgXCm460ib7H/Wq7e9oL5VL6S2BxaObxwIcag0g==", + "underscore-contrib": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", + "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", "dev": true, "requires": { - "jscodeshift": "^0.4.0" + "underscore": "1.6.0" }, "dependencies": { - "ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", - "dev": true - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "ast-types": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.10.1.tgz", - "integrity": "sha512-UY7+9DPzlJ9VM8eY0b2TUZcZvF+1pO0hzMtAyjBYKhOmnvRlqYNYnWdtsMj0V16CGaMlpL0G1jnLbLo4AyotuQ==", - "dev": true - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", - "dev": true, - "requires": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" - } - }, - "colors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.0.tgz", - "integrity": "sha512-EDpX3a7wHMWFA7PUHWPHNWqOxIIRSJetuwl0AS5Oi/5FMV8kWm69RTlgm00GKjBO1xFHMtBbL49yRtMMdticBw==", - "dev": true - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "jscodeshift": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.4.1.tgz", - "integrity": "sha512-iOX6If+hsw0q99V3n31t4f5VlD1TQZddH08xbT65ZqA7T4Vkx68emrDZMUOLVvCEAJ6NpAk7DECe3fjC/t52AQ==", - "dev": true, - "requires": { - "async": "^1.5.0", - "babel-plugin-transform-flow-strip-types": "^6.8.0", - "babel-preset-es2015": "^6.9.0", - "babel-preset-stage-1": "^6.5.0", - "babel-register": "^6.9.0", - "babylon": "^6.17.3", - "colors": "^1.1.2", - "flow-parser": "^0.*", - "lodash": "^4.13.1", - "micromatch": "^2.3.7", - "node-dir": "0.1.8", - "nomnom": "^1.8.1", - "recast": "^0.12.5", - "temp": "^0.8.1", - "write-file-atomic": "^1.2.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "nomnom": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", - "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", - "dev": true, - "requires": { - "chalk": "~0.4.0", - "underscore": "~1.6.0" - } - }, - "recast": { - "version": "0.12.9", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.12.9.tgz", - "integrity": "sha512-y7ANxCWmMW8xLOaiopiRDlyjQ9ajKRENBH+2wjntIbk3A6ZR1+BLQttkmSHMY7Arl+AAZFwJ10grg2T6f1WI8A==", - "dev": true, - "requires": { - "ast-types": "0.10.1", - "core-js": "^2.4.1", - "esprima": "~4.0.0", - "private": "~0.1.5", - "source-map": "~0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", - "dev": true - }, "underscore": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", @@ -7506,57 +1646,11 @@ } } }, - "webpack-cli": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-2.1.4.tgz", - "integrity": "sha512-dcxBcTPhKczWHYE9jh8MoHGQFuJxfqshZ3XSNFZ8o34heVvkqNvSRbMKy17NML+XUea7CXLzHWDg7a0GsBp7Pg==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "diff": "^3.5.0", - "enhanced-resolve": "^4.0.0", - "envinfo": "^5.7.0", - "glob-all": "^3.1.0", - "global-modules": "^1.0.0", - "got": "^8.3.1", - "import-local": "^1.0.0", - "inquirer": "^5.2.0", - "interpret": "^1.1.0", - "jscodeshift": "^0.5.0", - "listr": "^0.14.1", - "loader-utils": "^1.1.0", - "lodash": "^4.17.10", - "log-symbols": "^2.2.0", - "mkdirp": "^0.5.1", - "p-each-series": "^1.0.0", - "p-lazy": "^1.0.0", - "prettier": "^1.12.1", - "supports-color": "^5.4.0", - "v8-compile-cache": "^2.0.0", - "webpack-addons": "^1.1.5", - "yargs": "^11.1.0", - "yeoman-environment": "^2.1.1", - "yeoman-generator": "^2.0.5" - } - }, - "webpack-sources": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", - "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true }, "which": { "version": "1.3.1", @@ -7573,13 +1667,13 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "worker-farm": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", - "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "requires": { - "errno": "~0.1.7" + "string-width": "^1.0.2 || 2" } }, "wrap-ansi": { @@ -7635,150 +1729,204 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write-file-atomic": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", - "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - }, "xmlcreate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=", "dev": true }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "yargs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", + "yargs-unparser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", + "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" + "flat": "^4.1.0", + "lodash": "^4.17.11", + "yargs": "^12.0.5" }, "dependencies": { - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true - } - } - }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - }, - "yeoman-environment": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.1.1.tgz", - "integrity": "sha512-IBLwCUrJrDxBYuwdYm1wuF3O/CR2LpXR0rFS684QOrU6x69DPPrsdd20dZOFaedZ/M9sON7po73WhO3I1CbgNQ==", - "dev": true, - "requires": { - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^3.1.0", - "diff": "^3.3.1", - "escape-string-regexp": "^1.0.2", - "globby": "^8.0.1", - "grouped-queue": "^0.3.3", - "inquirer": "^5.2.0", - "is-scoped": "^1.0.0", - "lodash": "^4.17.10", - "log-symbols": "^2.1.0", - "mem-fs": "^1.1.0", - "strip-ansi": "^4.0.0", - "text-table": "^0.2.0", - "untildify": "^3.0.2" - } - }, - "yeoman-generator": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-2.0.5.tgz", - "integrity": "sha512-rV6tJ8oYzm4mmdF2T3wjY+Q42jKF2YiiD0VKfJ8/0ZYwmhCKC9Xs2346HVLPj/xE13i68psnFJv7iS6gWRkeAg==", - "dev": true, - "requires": { - "async": "^2.6.0", - "chalk": "^2.3.0", - "cli-table": "^0.3.1", - "cross-spawn": "^6.0.5", - "dargs": "^5.1.0", - "dateformat": "^3.0.3", - "debug": "^3.1.0", - "detect-conflict": "^1.0.0", - "error": "^7.0.2", - "find-up": "^2.1.0", - "github-username": "^4.0.0", - "istextorbinary": "^2.2.1", - "lodash": "^4.17.10", - "make-dir": "^1.1.0", - "mem-fs-editor": "^4.0.0", - "minimist": "^1.2.0", - "pretty-bytes": "^4.0.2", - "read-chunk": "^2.1.0", - "read-pkg-up": "^3.0.0", - "rimraf": "^2.6.2", - "run-async": "^2.0.0", - "shelljs": "^0.8.0", - "text-table": "^0.2.0", - "through2": "^2.0.0", - "yeoman-environment": "^2.0.5" - }, - "dependencies": { - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { - "lodash": "^4.17.10" + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/package.json b/package.json index 4986a9c..3639be4 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,13 @@ "version": "0.0.2", "description": "Chord player that can load different styles", "main": "dist/playback.js", + "type": "module", + "types": "types/playback.d.ts", "scripts": { - "test": "node test/test.bundle.js", - "build-grammar": "nearleyc src/parser/grammar.ne -o src/parser/grammar.js", - "build": "node_modules/.bin/webpack", - "build-watch": "node_modules/.bin/webpack --watch" + "test": "TS_NODE_IGNORE=\"/node_modules|(ts$)/\" npx ts-mocha -p test/tsconfig.json test/*.ts", + "build-grammar": "npx nearleyc src/parser/grammar.ne -o src/parser/grammar.js", + "build": "npx rollup -c; # npm run build-declarations", + "build-declarations": "npx tsc -d --emitDeclarationOnly --declarationDir types/" }, "repository": { "type": "git", @@ -20,12 +22,24 @@ }, "homepage": "https://github.com/notochord/playback#readme", "devDependencies": { + "@types/chai": "^4.2.0", + "@types/mocha": "^5.2.7", + "chai": "^4.2.0", "jsdoc": "^3.5.5", - "on-build-webpack": "^0.1.0", - "webpack": "^4.10.2", - "webpack-cli": "^2.1.4" + "mocha": "^6.1.4", + "nearley": "2.13.0", + "rollup": "^1.17.0", + "rollup-plugin-alias": "^1.5.2", + "rollup-plugin-banner": "^0.2.0", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-terser": "^5.1.1", + "rollup-plugin-typescript": "^1.0.1", + "ts-mocha": "^7.0.0", + "ts-node": "^8.3.0", + "tslib": "^1.10.0", + "typescript": "^3.5.3" }, "dependencies": { - "notochord-song": "git+https://github.com/notochord/notochord-song.git#0.1.2" + "notochord-song": "git+https://github.com/notochord/notochord-song.git#1.1.0" } } diff --git a/playground/index.html b/playground/index.html new file mode 100644 index 0000000..c5f143c --- /dev/null +++ b/playground/index.html @@ -0,0 +1,28 @@ + + + Playback Browser Test + + + + + + \ No newline at end of file diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..40a2b4e --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,60 @@ +import typescript from 'rollup-plugin-typescript'; +import { terser } from 'rollup-plugin-terser'; +import banner from 'rollup-plugin-banner'; +import alias from 'rollup-plugin-alias'; + +const preamble = 'playback by Jacob Bloom\nThis software is provided as-is, yadda yadda yadda'; + +export default [ + { + input: './src/playback.ts', + output: { + file: './dist/playback.cjs', + format: 'cjs' + }, + external: ['tonal'], + plugins: [ + typescript(), + banner(preamble) + ] + }, + { + input: './src/playback.ts', + output: { + file: './dist/playback.node.mjs', + format: 'esm' + }, + external: ['tonal'], + plugins: [ + typescript(), + banner(preamble) + ] + }, + { + input: './src/playback.ts', + output: { + file: './dist/playback.web.mjs', + format: 'esm' + }, + external: ['https://dev.jspm.io/tonal@2.2.2'], + plugins: [ + alias({tonal: 'https://dev.jspm.io/tonal@2.2.2'}), + typescript(), + banner(preamble) + ] + }, + /*{ + input: './src/playback.ts', + output: { + file: './dist/playback.min.js', + name: 'Song', + format: 'iife' + }, + plugins: [ + alias({tonal: './../node_modules/tonal/build/transpiled.js'}), + typescript(), + terser(), + banner(preamble) + ] + },*/ +]; \ No newline at end of file diff --git a/src/MIDI/Note.js b/src/MIDI/Note.ts similarity index 76% rename from src/MIDI/Note.js rename to src/MIDI/Note.ts index 7f97d43..641b5b0 100644 --- a/src/MIDI/Note.js +++ b/src/MIDI/Note.ts @@ -1,5 +1,6 @@ -import tonal from '../lib/tonal.min.js'; import drumJson from './drums.json.js'; +import * as _Tonal from 'tonal'; +const tonal = (_Tonal as any).default || _Tonal; /** * There are some inconsistencies with the official MIDI drum names, this @@ -26,34 +27,22 @@ let AwaitingDrum = Symbol('AwaitingDrum'); export {AwaitingDrum}; export class Note { + public time: number; // The note's time, in beats. + public pitch: string | symbol; // A string representing the pitch and octave of the note (e.g. A4) + public duration: number; // The note's duration, in beats. + public volume: number; // The note's volume, as a float 0-1 (inclusive). + /** * @param {Object} opts Options object. * @param {number} opts.time The note's time, in beats. - * @param {string} opts.pitch A string representing the pitch and octave of the note. e.x. 'A4' + * @param {string | symbol} opts.pitch A string representing the pitch and octave of the note. e.x. 'A4' * @param {number} opts.duraion The note's duration, in beats. * @param {number} opts.volume The note's volume, as a float 0-1 (inclusive). */ constructor(opts) { - /** - * The note's time, in beats. - * @type {number} - */ this.time = opts.time; - /** - * A string representing the pitch and octave of the note. - * @type {string} - * @example 'A4' - */ this.pitch = opts.pitch; - /** - * The note's duration, in beats. - * @type {number} - */ this.duration = opts.duration; - /** - * The note's volume, as a float 0-1 (inclusive). - * @type {number} - */ this.volume = opts.volume; } /** @@ -82,8 +71,8 @@ export class Note { } export class NoteSet extends Array { - constructor() { + constructor(...args) { super(); - this.push(...arguments); + this.push(...args); } } diff --git a/src/PlaybackStyle/PlaybackStyle.js b/src/PlaybackStyle/PlaybackStyle.ts similarity index 75% rename from src/PlaybackStyle/PlaybackStyle.js rename to src/PlaybackStyle/PlaybackStyle.ts index 0330bf1..be76e18 100644 --- a/src/PlaybackStyle/PlaybackStyle.js +++ b/src/PlaybackStyle/PlaybackStyle.ts @@ -1,17 +1,24 @@ -import {load} from '../loader/loader.js'; -import {parse} from '../parser/parser.js'; -import {NoteSet} from '../MIDI/Note.js'; +import {load} from '../loader/loader'; +import {parse} from '../parser/parser'; +import {NoteSet} from '../MIDI/Note'; +import GlobalScope from '../ast/GlobalScope'; export default class PlaybackStyle { + + private mainPath: string; + private ASTs: Map; + private initialized: boolean; + private main: GlobalScope; + /** * Set the main ast (the one that plays all its instruments by default). * @param {ast.GlobalScope} main the main ast * @param {Map.} asts A map of asts by their path */ constructor(mainPath) { - this._mainPath = mainPath; - this._ASTs = new Map(); - this._initialized = false; + this.mainPath = mainPath; + this.ASTs = new Map(); + this.initialized = false; } /** * Parse each file, pull its dependencies, put it all in a cache, rinse and @@ -19,7 +26,7 @@ export default class PlaybackStyle { * @private */ async _loadDependencies() { - let pendingDependencies = [this._mainPath]; + let pendingDependencies = [this.mainPath]; let dependencyPath; // @TODO: verify that dependencies have compatible time signature to main while(dependencyPath = pendingDependencies.pop()) { @@ -30,18 +37,18 @@ export default class PlaybackStyle { throw new Error(`Couldn't locate imported style "${dependencyPath}".`); } let ast = await parse(rawfile); - this._ASTs.set(dependencyPath, ast); + this.ASTs.set(dependencyPath, ast); ast.init(); for(let newDependency of ast.dependencies) { - if(!this._ASTs.has(newDependency)) { + if(!this.ASTs.has(newDependency)) { pendingDependencies.push(newDependency); } } } - this._main = this._ASTs.get(this._mainPath); + this.main = this.ASTs.get(this.mainPath); } _link() { - this._main.link(this._ASTs); + this.main.link(this.ASTs); } /** * Initialize the style, which includes loading dependencies and linking @@ -50,7 +57,7 @@ export default class PlaybackStyle { async init() { await this._loadDependencies(); this._link(); - this._initialized = true; + this.initialized = true; } /** * Compile a song into a set of MIDI-like note instructions. @@ -59,22 +66,22 @@ export default class PlaybackStyle { * instructions. */ compile(song) { - if(!this._initialized) { + if(!this.initialized) { throw new Error('PlayBack style must be initialized before compiling'); } let songIterator = song[Symbol.iterator](); let instruments = this.getInstruments(); let notes = new Map(); - let beatsPerMeasure = this._main.vars.get('time-signature')[0]; + let beatsPerMeasure = this.main.vars.get('time-signature')[0]; let totalPastBeats = 0; for(let instrument of instruments) notes.set(instrument, new NoteSet()); let nextValue; while(nextValue = songIterator.next(), nextValue.done == false) { - let thisMeasureTracks = this._main.execute(songIterator); + let thisMeasureTracks = this.main.execute(songIterator); for(let [instrument, thisMeasureNotes] of thisMeasureTracks) { for(let note of thisMeasureNotes) { note.time += totalPastBeats; - if(this._main.vars.get('swing')) { + if(this.main.vars.get('swing')) { let int_part = Math.floor(note.time); let float_part = note.time - int_part; if(float_part <= 0.5) { @@ -95,6 +102,6 @@ export default class PlaybackStyle { return notes; } getInstruments() { - return this._main.getInstruments(); + return this.main.getInstruments(); } } diff --git a/src/Player/Player.js b/src/Player/Player.ts similarity index 80% rename from src/Player/Player.js rename to src/Player/Player.ts index 3c2e6c5..67c2263 100644 --- a/src/Player/Player.js +++ b/src/Player/Player.ts @@ -1,6 +1,12 @@ import Soundfont from '../lib/soundfont-player.js'; +import PlaybackStyle from '../PlaybackStyle/PlaybackStyle'; export default class Player { + private style: PlaybackStyle + private initialized: boolean; + + public soundfonts: Map; + public context: AudioContext; /** * Loads the necessary soundfonts and plays a song in a PlaybackStyle in the * browser. @@ -8,17 +14,17 @@ export default class Player { * it. Otherwise it'll make its own. */ constructor(context) { - this._style = null; + this.style = null; this.context = context || new AudioContext({latencyHint: "playback"}); - this._initialized = false; - window.player = this; + this.initialized = false; + (window as any).player = this; } async setStyle(style) { - this._style = style; + this.style = style; if(!style._initialized) { await style.init(); } - this._initialized = false; + this.initialized = false; this.soundfonts = new Map(); let promises = []; for(let instrument of style.getInstruments()) { @@ -28,7 +34,7 @@ export default class Player { // @TODO: open an issue there sfpromise = Soundfont.instrument(this.context, instrument, { isSoundfontUrl: () => true, - nameToUrl: () => url + nameToUrl: () => instrument }); } else if(instrument == 'percussion') { sfpromise = Soundfont.instrument(this.context, instrument, {soundfont: 'FluidR3_GM'}); @@ -42,13 +48,13 @@ export default class Player { ); } await Promise.all(promises); - this._initialized = true; + this.initialized = true; } play(song) { - if(!this._style) { + if(!this.style) { throw new Error('No style selected'); } - if(!this._initialized) { + if(!this.initialized) { throw new Error('A style hasn\'t finished loading'); } @@ -56,7 +62,7 @@ export default class Player { this.context.resume(); } - let compiledSong = this._style.compile(song); + let compiledSong = this.style.compile(song); let tempoCoef = 0.4; // WHATEVER IDC HOW ANYTHING WORKS let startTime = this.context.currentTime + 1; diff --git a/src/ast/ArgumentOperators.js b/src/ast/ArgumentOperators.ts similarity index 62% rename from src/ast/ArgumentOperators.js rename to src/ast/ArgumentOperators.ts index cf27759..5ba64dd 100644 --- a/src/ast/ArgumentOperators.js +++ b/src/ast/ArgumentOperators.ts @@ -1,27 +1,35 @@ -import {Nil, cast_bool} from './type_utils.js'; +import {Nil, cast_bool} from './type_utils'; +import Scope from './Scope'; +import SongIterator from 'notochord-song/types/songiterator'; +type Anchor = 'KEY' | 'NEXT' | 'STEP' | 'ARPEGGIATE'; export class AnchorArgument { - constructor(anchor) { + public anchor: Anchor; + + constructor(anchor: Anchor) { this.anchor = anchor; } } class BooleanOperator { - constructor() { - this.args = [...arguments]; + public args: any[]; + public scope: Scope; + + constructor(...args) { + this.args = args; } link(ASTs, parentStyle, parentTrack) { this.args.forEach(arg => { if(arg.link) arg.link(ASTs, parentStyle, parentTrack); }); } - init(scope) { + init(scope: Scope) { this.scope = scope this.args.forEach(arg => { if(arg.init) arg.init(scope); }); } - resolve_args(songIterator) { + resolve_args(songIterator: SongIterator) { return this.args.map(arg => { if(arg.execute) { return arg.execute(songIterator); @@ -33,19 +41,19 @@ class BooleanOperator { } export class BooleanNot extends BooleanOperator { - constructor() { - super(...arguments); + constructor(...args) { + super(...args); } - execute(songIterator) { + execute(songIterator: SongIterator) { let args = this.resolve_args(songIterator); return !cast_bool(args[0]); } } export class BooleanAnd extends BooleanOperator { - constructor() { - super(...arguments); + constructor(...args) { + super(...args); } - execute(songIterator) { + execute(songIterator: SongIterator) { // sorry no short-circuiting because this code is prettier // @TODO: add short-circuiting if this actually makes it too slow let args = this.resolve_args(songIterator); @@ -53,10 +61,10 @@ export class BooleanAnd extends BooleanOperator { } } export class BooleanOr extends BooleanOperator { - constructor() { - super(...arguments); + constructor(...args) { + super(...args); } - execute(songIterator) { + execute(songIterator: SongIterator) { let args = this.resolve_args(songIterator); return cast_bool(args[0]) || cast_bool(args[1]); } diff --git a/src/ast/BeatGroups.js b/src/ast/BeatGroups.ts similarity index 76% rename from src/ast/BeatGroups.js rename to src/ast/BeatGroups.ts index 08a4a51..5545f21 100644 --- a/src/ast/BeatGroups.js +++ b/src/ast/BeatGroups.ts @@ -1,13 +1,19 @@ import { MelodicBeatInDrumBeatGroupError -} from './errors.js'; -import {Nil} from './type_utils.js'; -import {AwaitingDrum, Note, NoteSet} from '../MIDI/Note.js'; -import {MelodicBeatLiteral} from './BeatLiterals.js'; -import FunctionCall from './FunctionCall.js'; +} from './errors'; +import {Nil} from './type_utils'; +import {AwaitingDrum, Note, NoteSet} from '../MIDI/Note'; +import {MelodicBeatLiteral} from './BeatLiterals'; +import FunctionCall from './FunctionCall'; +import Scope from './Scope'; +import SongIterator from 'notochord-song/types/songiterator'; export class BeatGroupLiteral { - constructor(measures) { + public measures: Measure[]; + public scope: Scope; + public parentBeatGroup: BeatGroupLiteral; + + constructor(measures: Measure[]) { this.measures = measures; this.scope = null; } @@ -22,7 +28,7 @@ export class BeatGroupLiteral { let offset = i * 4; // @TODO: pull in actual meter somehow let measureNotes = this.measures[i].execute(songIterator); if(measureNotes === Nil) return Nil; // lets a/s abort the beatgroup - for(let measureNote of measureNotes) { + for(let measureNote of measureNotes as NoteSet) { measureNote.time += offset; joinedMeasures.push(measureNote); } @@ -51,21 +57,27 @@ export class BeatGroupLiteral { } export class Measure { - constructor(beats) { + public beats: MelodicBeatLiteral[] | DrumBeatGroupLiteral[]; + public beatsPerMeasure: number; + public scope: Scope; + public parentBeatGroup: BeatGroupLiteral; + public indexInBeatGroup: number; + + constructor(beats: MelodicBeatLiteral[] | DrumBeatGroupLiteral[]) { this.beats = beats; this.beatsPerMeasure = null; this.scope = null; } calculateDurationAfter(beatIndex) { let currentBeat = this.beats[beatIndex]; - let currentBeatTime = currentBeat.getTime(); + let currentBeatTime = (currentBeat as MelodicBeatLiteral).getTime(); let nextBeatTime; if(beatIndex + 1 >= this.beats.length) { nextBeatTime = this.beatsPerMeasure + 1; } else { let nextBeat = this.beats[beatIndex + 1]; - nextBeatTime = nextBeat.getTime(); + nextBeatTime = (nextBeat as MelodicBeatLiteral).getTime(); } return nextBeatTime - currentBeatTime; } @@ -86,10 +98,10 @@ export class Measure { beat.init(scope, this, i); }); } - execute(songIterator) { + execute(songIterator: SongIterator) { // clear cached notes (used for STEP/ARPEGGIATE interpolation) for(let beat of this.beats) { - beat.cachedAnchor = null; + if(beat instanceof MelodicBeatLiteral) beat.cachedAnchor = null; } // each beat returns a NoteSet since it could be a chord or whatever let joined = new NoteSet(); @@ -103,6 +115,10 @@ export class Measure { } export class DrumBeatGroupLiteral { + public beatGroup: BeatGroupLiteral; + public scope: Scope; + public drum: string; + constructor(drum, beatGroup) { this.drum = drum; this.beatGroup = beatGroup; // for now there's no diff in functionality... @@ -113,7 +129,7 @@ export class DrumBeatGroupLiteral { if(this.beatGroup.init) this.beatGroup.init(scope); } link() {return;} // @TODO: I think patterncalls are allowed here? - execute(songIterator) { + execute(songIterator: SongIterator) { let notes = this.beatGroup.execute(songIterator); for(let note of notes) { if(note.pitch === AwaitingDrum) { diff --git a/src/ast/BeatLiterals.js b/src/ast/BeatLiterals.ts similarity index 86% rename from src/ast/BeatLiterals.js rename to src/ast/BeatLiterals.ts index 8bac5d6..6209cee 100644 --- a/src/ast/BeatLiterals.js +++ b/src/ast/BeatLiterals.ts @@ -1,8 +1,30 @@ //import {Nil} from './type_utils.js'; import tonal from '../lib/tonal.min.js'; -import {AwaitingDrum, Note, NoteSet} from '../MIDI/Note.js'; +import {AwaitingDrum, Note, NoteSet} from '../MIDI/Note'; +import Scope from './Scope'; +import { Measure } from './BeatGroups'; +import SongIterator from 'notochord-song/types/songiterator'; + +type TimePart = { + time: 'auto' | number; + flag?: 'STACCATO' | 'ACCENTED' +}; +type PitchPart = { + degree: number; + anchor?: 'KEY' | 'NEXT' | 'STEP' | 'ARPEGGIATE'; + roll?: 'ROLL_UP' | 'ROLL_DOWN'; + chord: boolean; // actually undefined | true but ts doesn't need to know that +}; export class MelodicBeatLiteral { + public time: TimePart; + public pitch: PitchPart; + public octave: number | 'inherit'; + public scope: Scope; + public parentMeasure: Measure; + public indexInMeasure: number; + public cachedAnchor: any; + constructor(opts) { this.time = opts.time || {time: 'auto'}; this.pitch = opts.pitch; @@ -67,7 +89,7 @@ export class MelodicBeatLiteral { } return outPitches; } - static getAnchorChord(anchor, songIterator, currentTime) { + static getAnchorChord(anchor, songIterator: SongIterator, currentTime) { let anchorChord; switch(anchor) { case 'KEY': { @@ -96,6 +118,7 @@ export class MelodicBeatLiteral { // crawl backward through this measure to get the last set beat let lastSetBeat = Math.floor(currentTime); let iteratorMeasure = songIterator.getRelative(0); + if(!iteratorMeasure) break; do { const beat = iteratorMeasure.beats[lastSetBeat] anchorChord = beat && beat.chord; @@ -113,16 +136,16 @@ export class MelodicBeatLiteral { return tonal.Note.from({oct: octave}, rootPC); } getAnchorData(songIterator) { - let anchorChord = this.constructor.getAnchorChord( + let anchorChord = MelodicBeatLiteral.getAnchorChord( this.pitch.anchor, songIterator, this.getTime() ); - let root = this.constructor.anchorChordToRoot( + let root = MelodicBeatLiteral.anchorChordToRoot( anchorChord, this.pitch.degree, this.getOctave() ); return [anchorChord, root]; } - getPitches(songIterator) { + getPitches(songIterator: SongIterator) { let [anchorChord, root] = this.getAnchorData(songIterator); let pitches; @@ -190,6 +213,12 @@ export class MelodicBeatLiteral { } export class DrumBeatLiteral { + public time: number; + public accented: boolean; + public scope: Scope; + public parentMeasure: Measure; + public indexInMeasure: number; + constructor(opts) { this.time = opts.time; this.accented = opts.accented || false; diff --git a/src/ast/ConfigStatements.js b/src/ast/ConfigStatements.ts similarity index 50% rename from src/ast/ConfigStatements.js rename to src/ast/ConfigStatements.ts index 28f8a96..e91f787 100644 --- a/src/ast/ConfigStatements.js +++ b/src/ast/ConfigStatements.ts @@ -1,38 +1,44 @@ -import Scope from './Scope.js'; +import Scope from './Scope'; +import FunctionCall from './FunctionCall'; +import GlobalScope from './GlobalScope'; export class MetaStatement extends Scope { - constructor(function_calls) { + public functionCalls: FunctionCall[]; + + constructor(functionCalls: FunctionCall[]) { super(); this.name = '@meta'; this.type = '@meta'; - this.function_calls = function_calls; + this.functionCalls = functionCalls; } - init(scope) { + init(scope: GlobalScope) { this.scope = scope; // nothing in here can be dynamic so resolve these at compile time - for(let function_call of this.function_calls) { - function_call.init(this); - function_call.execute(); + for(let functionCall of this.functionCalls) { + functionCall.init(this); + functionCall.execute(); } - scope.meta = this.vars; + scope.metadata = this.vars; } } export class OptionsStatement extends Scope { - constructor(function_calls) { + public functionCalls: FunctionCall[]; + + constructor(functionCalls) { super(); this.name = '@options'; this.type = '@options'; - this.function_calls = function_calls; + this.functionCalls = functionCalls; } - init(scope) { + init(scope: GlobalScope) { // nothing in here /should/ be dynamic so resolve these at compile time - for(let function_call of this.function_calls) { - function_call.init(this); - function_call.execute(); + for(let functionCall of this.functionCalls) { + functionCall.init(this); + functionCall.execute(); } this.scope = scope; @@ -43,6 +49,9 @@ export class OptionsStatement extends Scope { } export class ImportStatement { + public path: string; + public identifier: string; + constructor(path, identifier) { this.path = path; this.identifier = identifier; diff --git a/src/ast/FunctionCall.js b/src/ast/FunctionCall.ts similarity index 62% rename from src/ast/FunctionCall.js rename to src/ast/FunctionCall.ts index 8141bc7..80928a0 100644 --- a/src/ast/FunctionCall.js +++ b/src/ast/FunctionCall.ts @@ -1,13 +1,27 @@ -import * as function_data from './function_data.js'; -import {FunctionNameError} from './errors.js'; +import * as function_data from './function_data'; +import {FunctionNameError} from './errors'; +import SongIterator from 'notochord-song/types/songiterator'; +import Scope from './Scope'; + +type FunctionDefinition = { + types: (Function|string)[] | '*'; + scope: 'meta' | 'options' | 'no-config' | 'pattern' | 'no-meta'; + returns: string | Function | symbol; + execute: (args: any[], songIterator: SongIterator, scope: Scope) => any; +}; /** * If the value is a FunctionCall, call it and return the returned value. * Otherwise, return the value itself. * @private */ // @TODO: if this is needed elsewhere, put it somewhere useful. - export default class FunctionCall { + public identifier: string; + public definition: FunctionDefinition; + public args: any[]; + public scope: Scope; + public returns: string | Function | symbol; + /** * @constructor * @param {string} identifier The name of the function. Ideally it should @@ -19,7 +33,7 @@ export default class FunctionCall { this.args = args; this.scope = null; } - init(scope) { + init(scope: Scope) { this.scope = scope; if(!this.definition) { throw new FunctionNameError(this.identifier, this.scope); @@ -38,22 +52,22 @@ export default class FunctionCall { if(arg.link) arg.link(ASTs, parentStyle, parentTrack); }); } - execute(songIterator) { + execute(songIterator?: SongIterator) { // Compile-type functions don't require a SongIterator if(!this.scope) throw new Error('function not initialized :('); - let evaluated_args = this.args.map(arg => { + let evaluatedArgs = this.args.map(arg => { if(arg.execute) { return arg.execute(songIterator); } else { return arg; } }); - let return_value = this.definition.execute( - evaluated_args, + let returnValue = this.definition.execute( + evaluatedArgs, songIterator, this.scope); - if(return_value === undefined) { + if(returnValue === undefined) { throw new Error(`Function "${this.identifier}" can return undefined`); } - return return_value; + return returnValue; } } diff --git a/src/ast/GlobalScope.js b/src/ast/GlobalScope.ts similarity index 71% rename from src/ast/GlobalScope.js rename to src/ast/GlobalScope.ts index 07c68a4..6dc2c4e 100644 --- a/src/ast/GlobalScope.js +++ b/src/ast/GlobalScope.ts @@ -1,11 +1,22 @@ -import {Nil} from './type_utils.js'; -import {NoteSet} from '../MIDI/Note.js'; -import {NoSuchStyleError, NoSuchTrackError} from './errors.js'; -import Scope from './Scope.js'; -import {MetaStatement, OptionsStatement, ImportStatement} from './ConfigStatements.js'; -import {TrackStatement, TrackCall} from './Track.js'; +import {Nil} from './type_utils'; +import {NoteSet} from '../MIDI/Note'; +import {NoSuchStyleError, NoSuchTrackError} from './errors'; +import Scope from './Scope'; +import {MetaStatement, OptionsStatement, ImportStatement} from './ConfigStatements'; +import {TrackStatement, TrackCall} from './Track'; +import SongIterator from 'notochord-song/types/songiterator'; + +type Statement = MetaStatement | OptionsStatement | ImportStatement | TrackStatement | TrackCall; export default class GlobalScope extends Scope { + public statements: Statement[]; + public metaStatements: (MetaStatement | OptionsStatement)[]; + public importedStyles: Map; + public dependencies: string[]; + public tracks: Map; + public trackCalls: TrackCall[]; + public metadata?: Map; + constructor(statements) { super(); @@ -21,7 +32,7 @@ export default class GlobalScope extends Scope { this.vars.set('tempo', 120); this.tracks = new Map(); - this.meta = []; + this.metaStatements = []; // @TODO: stop circular dependencies? cache them and mark one as mom this.importedStyles = new Map(); this.trackCalls = []; @@ -31,7 +42,7 @@ export default class GlobalScope extends Scope { if(statement instanceof MetaStatement || statement instanceof OptionsStatement) { // @TODO: make sure there's exactly 1 meta block - this.meta.push(statement); + this.metaStatements.push(statement); } else if(statement instanceof ImportStatement) { this.importedStyles.set(statement.identifier, statement.path); this.dependencies.push(statement.path); @@ -42,7 +53,7 @@ export default class GlobalScope extends Scope { } } // handle meta blocks first since they set variables in own scope - this.meta.forEach(statement => statement.init(this)); + this.metaStatements.forEach(statement => statement.init(this)); // -- handle importing before statements -- @@ -68,8 +79,8 @@ export default class GlobalScope extends Scope { track.link(ASTs, this); } } - execute(songIterator) { - let trackNoteMap = new Map(); + execute(songIterator: SongIterator) { + let trackNoteMap = new Map(); for(let [, track] of this.tracks) { let trackNotes = track.execute(songIterator); if(trackNotes !== Nil) trackNoteMap.set(track.instrument, trackNotes); @@ -77,7 +88,7 @@ export default class GlobalScope extends Scope { return trackNoteMap; } getInstruments() { - let instruments = new Set(); + let instruments = new Set(); for(let [, track] of this.tracks) { instruments.add(track.instrument); } diff --git a/src/ast/Pattern.js b/src/ast/Pattern.ts similarity index 82% rename from src/ast/Pattern.js rename to src/ast/Pattern.ts index fd6c479..6181e89 100644 --- a/src/ast/Pattern.js +++ b/src/ast/Pattern.ts @@ -1,5 +1,5 @@ -import {Nil, cast_bool} from './type_utils.js'; -import {NoteSet} from '../MIDI/Note.js'; +import {Nil, cast_bool} from './type_utils'; +import {NoteSet} from '../MIDI/Note'; import { TooManyBeatsError, NoSuchStyleError, @@ -8,8 +8,14 @@ import { } from './errors.js'; import Scope from './Scope.js'; import FunctionCall from './FunctionCall.js'; +import SongIterator from 'notochord-song/types/songiterator'; export class PatternExpressionGroup extends Scope { + public expressions: any[]; + public functionCalls: FunctionCall[]; + public nonFunctionCallExpressions: any[]; + public patternStatement: PatternStatement; + constructor(expressions) { super(); this.type = 'PatternExpressionGroup'; @@ -19,8 +25,8 @@ export class PatternExpressionGroup extends Scope { this.defaultVars.set('chance', 1); this.expressions = expressions; - this.function_calls = []; - this.non_function_call_expressions = []; + this.functionCalls = []; + this.nonFunctionCallExpressions = []; } init(scope, patternStatement = null) { super.init(scope); @@ -35,9 +41,9 @@ export class PatternExpressionGroup extends Scope { throw ['expression not initialized:', expression]; } if(expression instanceof FunctionCall) { - this.function_calls.push(expression); + this.functionCalls.push(expression); } else { - this.non_function_call_expressions.push(expression); + this.nonFunctionCallExpressions.push(expression); } }); } @@ -48,8 +54,8 @@ export class PatternExpressionGroup extends Scope { } execute(songIterator, callerIsTrack = false) { this.inherit(); - let beats = Nil; - for(let function_call of this.function_calls) { + let beats: NoteSet | symbol = Nil; + for(let function_call of this.functionCalls) { let return_value = function_call.execute(songIterator); if(return_value instanceof NoteSet) { if(beats !== Nil) { @@ -61,7 +67,7 @@ export class PatternExpressionGroup extends Scope { if(callerIsTrack && this.vars.get('private') === true) { return Nil; // if it's private we can give up now } - for(let expression of this.non_function_call_expressions) { + for(let expression of this.nonFunctionCallExpressions) { if(expression.execute) { expression = expression.execute(songIterator); } @@ -77,6 +83,9 @@ export class PatternExpressionGroup extends Scope { } export class PatternStatement extends PatternExpressionGroup { + public identifier: string; + public condition?: any; + constructor(opts) { if(opts.expression instanceof PatternExpressionGroup) { // unroll the redundant expression group @@ -100,7 +109,7 @@ export class PatternStatement extends PatternExpressionGroup { super.init(scope); if(this.condition && this.condition.init) this.condition.init(this); } - execute(songIterator, callerIsTrack) { + execute(songIterator: SongIterator, callerIsTrack = false) { if(this.condition) { let condition_value; if(this.condition.execute) { @@ -115,6 +124,13 @@ export class PatternStatement extends PatternExpressionGroup { } export class PatternCall { + public import?: string; + public track?: string; + public pattern: string; + public scope: Scope; + public patternStatement: PatternStatement; + public prettyprintname: string; + constructor(opts) { this.import = opts.import || null; this.track = opts.track || null; @@ -159,13 +175,16 @@ export class PatternCall { this); this.patternStatement = patternStatement; } - execute(songIterator) { + execute(songIterator: SongIterator) { // called patternStatement ignores private() return this.patternStatement.execute(songIterator); } } export class JoinedPatternExpression { + public patterns: any[]; + public scope: Scope; + constructor(patterns) { this.patterns = patterns; } @@ -180,7 +199,7 @@ export class JoinedPatternExpression { pattern.link(ASTs, parentStyle, parentTrack); }); } - execute(songIterator) { + execute(songIterator: SongIterator) { let noteSets = []; for(let pattern of this.patterns) { if(pattern.execute) { diff --git a/src/ast/Scope.js b/src/ast/Scope.ts similarity index 81% rename from src/ast/Scope.js rename to src/ast/Scope.ts index 7eb2bba..80dc631 100644 --- a/src/ast/Scope.js +++ b/src/ast/Scope.ts @@ -3,6 +3,12 @@ * which inherits settings from its parent scope but can overwrite them. */ export default class Scope { + public defaultVars: Map; + public vars: Map; + public name: string; + public type: string; + public scope: Scope; + constructor() { this.defaultVars = new Map(); this.vars = new Map(); diff --git a/src/ast/Track.js b/src/ast/Track.ts similarity index 77% rename from src/ast/Track.js rename to src/ast/Track.ts index 127993d..70bc495 100644 --- a/src/ast/Track.js +++ b/src/ast/Track.ts @@ -1,13 +1,23 @@ -import {Nil} from './type_utils.js'; +import {Nil} from './type_utils'; import { DrumBeatInMelodicBeatGroupError } from './errors.js'; -import {AwaitingDrum} from '../MIDI/Note.js'; -import Scope from './Scope.js'; -import FunctionCall from './FunctionCall.js'; -import {PatternStatement, PatternCall} from './Pattern.js'; +import {AwaitingDrum} from '../MIDI/Note'; +import Scope from './Scope'; +import FunctionCall from './FunctionCall'; +import {PatternStatement, PatternCall} from './Pattern'; +import SongIterator from 'notochord-song/types/songiterator'; +import {NoteSet} from '../MIDI/Note'; export class TrackStatement extends Scope { + public instrument: string; + public identifier: string; + public members: (FunctionCall | PatternStatement | PatternCall)[]; + + public functionCalls: FunctionCall[]; + public patterns: Map; + public patternCalls: PatternCall[]; + constructor(opts) { super(); this.name = opts.identifier; @@ -23,14 +33,14 @@ export class TrackStatement extends Scope { } init(scope) { super.init(scope); - this.function_calls = []; + this.functionCalls = []; this.patterns = new Map(); this.patternCalls = []; this.members.forEach(member => { // initialize them all now, var inheritence is handled during execution member.init(this); if(member instanceof FunctionCall) { - this.function_calls.push(member); + this.functionCalls.push(member); } else if(member instanceof PatternStatement) { this.patterns.set(member.identifier, member); } else if(member instanceof PatternCall) { @@ -52,7 +62,7 @@ export class TrackStatement extends Scope { this.inherit(); console.log(`executing TrackStatement "${this.name}"`); - this.function_calls.forEach(function_call => { + this.functionCalls.forEach(function_call => { function_call.execute(songIterator); }); @@ -68,7 +78,7 @@ export class TrackStatement extends Scope { console.log(' - Result:', result); // @TODO: handle multi-measure patterns (via locks?) if(result !== Nil) { - for(let note of result) { + for(let note of (result as NoteSet)) { if (note.pitch === AwaitingDrum) { throw new DrumBeatInMelodicBeatGroupError(pattern); } @@ -96,12 +106,16 @@ export class TrackStatement extends Scope { } } export class TrackCall { + public import: string; + public track: string; + public trackStatement: TrackStatement; + constructor(opts) { this.import = opts.import; this.track = opts.track; this.trackStatement = null; // will be set by the loader. } - execute(songIterator) { + execute(songIterator: SongIterator) { this.trackStatement.execute(songIterator); } } diff --git a/src/ast/ast_nodes.js b/src/ast/ast_nodes.ts similarity index 100% rename from src/ast/ast_nodes.js rename to src/ast/ast_nodes.ts diff --git a/src/ast/errors.js b/src/ast/errors.ts similarity index 96% rename from src/ast/errors.js rename to src/ast/errors.ts index 6258a63..c48d754 100644 --- a/src/ast/errors.js +++ b/src/ast/errors.ts @@ -7,8 +7,8 @@ class PlaybackError extends Error { /* Import-related errors */ export class ImportError extends PlaybackError { - constructor() { - super(...arguments); + constructor(message, scope) { + super(message, scope); } } export class NoSuchStyleError extends ImportError { diff --git a/src/ast/function_data.js b/src/ast/function_data.ts similarity index 96% rename from src/ast/function_data.js rename to src/ast/function_data.ts index ce39a87..6e7e1ff 100644 --- a/src/ast/function_data.js +++ b/src/ast/function_data.ts @@ -1,8 +1,10 @@ import tonal from '../lib/tonal.min.js'; -import {MelodicBeatLiteral} from './BeatLiterals.js'; -import {FunctionArgumentsError, FunctionScopeError} from './errors.js'; -import FunctionCall from './FunctionCall.js'; -import {Nil} from './type_utils.js'; +import {MelodicBeatLiteral} from './BeatLiterals'; +import {FunctionArgumentsError, FunctionScopeError} from './errors'; +import FunctionCall from './FunctionCall'; +import {Nil} from './type_utils'; +import SongIterator from 'notochord-song/types/songiterator'; +import Scope from './Scope'; let definitions = new Map(); @@ -110,7 +112,7 @@ let define = function(identifier, opts, func) { types: opts.types || '*', returns: opts.returns || '*', scope: opts.scope || 'no-meta', - execute: (args, songIterator, scope) => { + execute: (args: any[], songIterator: SongIterator, scope: Scope) => { let argErr = message => { throw new FunctionArgumentsError(message, scope); }; @@ -266,7 +268,7 @@ define('progression', } let actualMeasure = songIterator.getRelative(Number(i)); if(!actualMeasure) return false; - let actualChord = MelodicBeatLiteral.normalizeChord(actualMeasure[0]); + let actualChord = MelodicBeatLiteral.normalizeChord(actualMeasure.beats[0].chord); let actual = MelodicBeatLiteral.anchorChordToRoot( actualChord, 1, 4); if(actual != goal) return false; @@ -297,7 +299,8 @@ define('beat-defined', }, (args, songIterator, scope, argErr) => { let measure = songIterator.getRelative(0); - return measure[args[0]] !== null; + if(!measure) return false; + return measure.beats[args[0]].chord !== null; }); /*** pattern-only functions ***/ diff --git a/src/ast/type_utils.js b/src/ast/type_utils.ts similarity index 100% rename from src/ast/type_utils.js rename to src/ast/type_utils.ts diff --git a/src/lexer/lexer.js b/src/lexer/lexer.ts similarity index 100% rename from src/lexer/lexer.js rename to src/lexer/lexer.ts diff --git a/src/loader/loader-node.js b/src/loader/loader-node.js deleted file mode 100644 index bfc4a72..0000000 --- a/src/loader/loader-node.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Load a file. - * - * * Style locator algorithm: - * 1. If the path begins with http:// or https://, look at that URL - * 2. If the path begins with . or / look in the filesystem or at a relative URL - * 3. Otherwise, look in the styles folder in this repo (which will move to its - * own repo eventually). For these built-in styles, the .play file extension - * is not required. - * - * @param {string} path The path to the file to load. - * @return {string} The content of the file. - */ -export async function load(stylePath) { - let isHTTP = stylePath.startsWith('http://') || stylePath.startsWith('https://'); - if (isHTTP) { - console.log('TODO'); - return ''; - } else { - let isRelative = stylePath.startsWith('.') || stylePath.startsWith('/'); - if (!isRelative) { - let path = await import('path'); - stylePath = path.join(__dirname, '../../styles/', stylePath); - if (!stylePath.endsWith('.play')) stylePath += '.play'; - } - let fs = await import('fs'); - return await (new Promise((resolve, reject) => { - fs.readFile(stylePath, 'utf8', (err, data) => { - if (err) { - reject(err); - } else { - resolve(data); - } - }); - })); - } -} \ No newline at end of file diff --git a/src/loader/loader.js b/src/loader/loader.js deleted file mode 100644 index 36cb43b..0000000 --- a/src/loader/loader.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Load a file. - * - * Note: This version won't compile under webpack because import.meta isn't - * supported by their parser - * - * * Style locator algorithm: - * 1. If the path begins with http:// or https://, look at that URL - * 2. If the path begins with . or / look in the filesystem or at a relative URL - * 3. Otherwise, look in the styles folder in this repo (which will move to its - * own repo eventually). For these built-in styles, the .play file extension - * is not required. - * - * @param {string} path The path to the file to load. - * @return {string} The content of the file. - */ -export async function load(stylePath) { - let isHTTP = stylePath.startsWith('http://') || stylePath.startsWith('https://'); - let isRelative = stylePath.startsWith('.') || stylePath.startsWith('/'); - if (isHTTP || isRelative) { - return await fetch(stylePath).then(r => r.text()); - } else { - let modulePath = String(import.meta.url).replace(/[^\/]+$/, ''); - stylePath = modulePath + '../../styles/' + stylePath; - if (!stylePath.endsWith('.play')) stylePath += '.play'; - return await fetch(stylePath).then(r => r.text()); - } -}; diff --git a/src/loader/loader.ts b/src/loader/loader.ts new file mode 100644 index 0000000..c177575 --- /dev/null +++ b/src/loader/loader.ts @@ -0,0 +1,57 @@ +/** + * Load a file. + * + * * Style locator algorithm: + * 1. If the path begins with http:// or https://, look at that URL + * 2. If the path begins with . or / look in the filesystem or at a relative URL + * 3. Otherwise, look in the styles folder in this repo (which will move to its + * own repo eventually). For these built-in styles, the .play file extension + * is not required. + * + * @param {string} path The path to the file to load. + * @return {string} The content of the file. + */ +export async function load(stylePath) { + let isHTTP = stylePath.startsWith('http://') || stylePath.startsWith('https://'); + let isRelative = stylePath.startsWith('.') || stylePath.startsWith('/'); + if (typeof process === 'undefined') { + if (isHTTP || isRelative) { + return fetch(stylePath).then(r => r.text()); + } else { + let modulePath = ''; //String(import.meta.url).replace(/[^\/]+$/, ''); + stylePath = modulePath + '../../styles/' + stylePath; + if (!stylePath.endsWith('.play')) stylePath += '.play'; + return fetch(stylePath).then(r => r.text()); + } + } else { + if (isHTTP) { + const http = await import(stylePath.startsWith('https://') ? 'https' : 'http'); + return new Promise((resolve, reject) => { + http.get(stylePath, res => { + let body = ''; + res.setEncoding('utf8'); + res.on('data', data => body += data); + res.on('end', () => resolve(body)); + res.on('error', reject); + }); + }); + } + if (!isRelative) { + let path = await import('path'); + try { + stylePath = path.join(__dirname, '../../styles/', stylePath); + } catch {} + if (!stylePath.endsWith('.play')) stylePath += '.play'; + } + let fs = await import('fs'); + return (new Promise((resolve, reject) => { + fs.readFile(stylePath, 'utf8', (err, data) => { + if (err) { + reject(err); + } else { + resolve(data); + } + }); + })); + } +}; diff --git a/src/parser/grammar.ne b/src/parser/grammar.ne index 91d3b22..9c8a223 100644 --- a/src/parser/grammar.ne +++ b/src/parser/grammar.ne @@ -1,8 +1,8 @@ # import the lexer @preprocessor esmodule @{% -import lexer from '../lexer/lexer.js' ; -import * as ast from '../ast/ast_nodes.js'; +import lexer from '../lexer/lexer' ; +import * as ast from '../ast/ast_nodes'; %} @lexer lexer diff --git a/src/parser/parser.js b/src/parser/parser.ts similarity index 57% rename from src/parser/parser.js rename to src/parser/parser.ts index 61e81eb..033cad8 100644 --- a/src/parser/parser.js +++ b/src/parser/parser.ts @@ -1,5 +1,6 @@ import nearley from '../lib/nearley/nearley.js'; -import grammar from './grammar.js'; +import grammar from './grammar'; +import { GlobalScope } from '../ast/ast_nodes'; /** * Parses a string into a set of possible abstract systax trees (ASTs) trees of * objects representing the syntax of the file. @@ -11,21 +12,18 @@ import grammar from './grammar.js'; * tree might look like. * @private */ -export let string_to_ast = function string_to_ast(data) { +export async function getPossibleParses(data: string) { // Create a Parser object from our grammar. // (I don't think you can reset the parser so make a new one each time) const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar)); - - return new Promise(function(resolve, reject) { - try { - parser.feed(data); - } catch(err) { - // Because tabs screw up the formatting of SyntaxError messages. - err.message = err.message.replace(/\t/g, ' '); - reject(err); - } - resolve(parser.results); - }); + try { + parser.feed(data); + return parser.results as GlobalScope[]; + } catch(err) { + // Because tabs screw up the formatting of SyntaxError messages. + err.message = err.message.replace(/\t/g, ' '); + throw err; + } }; /** @@ -34,14 +32,10 @@ export let string_to_ast = function string_to_ast(data) { * @param {string} data The string to parse * @return {Promise.} The Abstract Systax Tree (AST). */ - export let parse = function parse(data) { - return new Promise(function(resolve, reject) { - string_to_ast(data) - .then(parses => { - if(!parses.length) { - throw new SyntaxError('Something went wrong, input not parseable.'); - } - resolve(parses[0]); - }); - }); - }; +export async function parse(data: string) { + const parses = await getPossibleParses(data); + if(!parses.length) { + throw new SyntaxError('Something went wrong, input not parseable.'); + } + return parses[0]; +}; \ No newline at end of file diff --git a/src/parser/test/styles/ambig.play b/src/parser/test/styles/ambig.play deleted file mode 100644 index 1dcf075..0000000 --- a/src/parser/test/styles/ambig.play +++ /dev/null @@ -1,18 +0,0 @@ -@track "percussion" as drums { - @pattern drums-mixed { - @pattern(a) & - @pattern(a) & - @pattern(a) & - @pattern(a) & - @pattern(a) - < 1 | 2 | 3 | 4 | 5 | 6 > - <1> - <1> - <1> - <1> - <1> - // comment 1 - // comment 2 - // comment 3 -- these should be parsed as 1 ws - } -} diff --git a/src/parser/test/styles/example.play b/src/parser/test/styles/example.play deleted file mode 100644 index f30d293..0000000 --- a/src/parser/test/styles/example.play +++ /dev/null @@ -1,96 +0,0 @@ -@meta { - name("Swing") - author("Jacob Bloom") - description("You know the drill") - playback-version(0.1) -} - -@options { - time-signature(4 4) - swing() // is there a way to reverse boolean functions? swing(false) -} - -@import "stdlib" as stdlib - -// ***** DRUMS ***** -@track "percussion" as drums { - @pattern snare-hits { - private() - "Acoustic Snare" choose( - <4> - <2.5> - <2.5 3.5 4.5> - ) - chance(3/10) // evaluates to 0.3 - volume(1) - } - // if not it returns nil, if we end up with nil just don't play lol - - @pattern hi-hat { - private() - "Open Hi-Hat" <1 2 2.5 3 4 4.5> & - "Closed Hi Hat" <2 4> // automatic overlay is stupid, simply throw when we get <> <> outside of args list - volume(0.1) - } - @pattern drums-mixed { - @pattern(snare-hits) & - @pattern(piano.hi-hat) & - @pattern(stdlib.drums.hi-hat) & - {"Bass Drum" <1 2 3 4> volume(0.2)} // scopes are ok a lot of places but can only be named via @pattern - // {...snare-hits} & {...hi-hat} & {"Bass Drum" <1 2 3 4> volume 0.2} - } -} - -@track(stdlib.jazz-guitar) - -// ***** PIANO ***** -@track "acoustic_grand_piano" as piano { // "as" required. - invertible() - octave(4) - - @pattern maybe3 { // patterns that are ok with or without 3rd beat in measure - choose( - // make it clear in docs that all notes are relative to the given chord - <1.5s:1c 2:1c 3.5:1c> - {<1:1c 2.5s:1c 3.5:1c> volume(.5)} // deepest scope wins - <1:1c 2.5:1c 3.5:1c 4.5:1c> - ) - volume ( .3 ) - } - @pattern no3 if(not beat-defined(3)) <1:1c:4 2.5:1c:4> - - @pattern multiMeasurePattern { - length(8) - <1 2 3 4 | 1 2 3 4> // this one solidifies <> as generic beat containers that could even contain partial measures a la <1 2>+<3 4> - // the second interpretation can include the first - } - - @pattern brainstorm if(not false) { - private() - <1:1 4/3:2 5/3:3 2:3 3:3 4:3> - } - - @pattern myPattern if(true and true) volume(1) - -} - -// ***** BASS ***** -@track "acoustic_bass" as bass { - volume(1) - octave(2) - invertible() - - @pattern walk1 if(not progression(1 1)) { - choose( - <:1 :s :s :n7> // covers (1,2,2.5,3,4) & (1,2,3,4,5) & (1,6.5,6,5,6) but risks things like (1,1,1.5,1.5,2) - <:1 :s :s :n2> - <:1 :3 :5 :n7> - <:1 :5 :3 :n7> - <:1 :a :a :n7> // tries to arpeggiate in the chord of 1, else the key of 1, toward the final beat (smartly up or down) - ) - } - - @pattern walk2 if(in-scale(1 n)) { - <:1 :s :s :n5> - } -} diff --git a/src/parser/test/test.js b/src/parser/test/test.js deleted file mode 100644 index d5c50fc..0000000 --- a/src/parser/test/test.js +++ /dev/null @@ -1,32 +0,0 @@ -import {load} from '../../loader/loader.js'; -import * as parser from '../parser.js'; -import assert from 'assert'; - -export default function() { - - // load a couple test files - // yes one promise can have multiple thens, I checked in chrome console - let styles_dir = './src/parser/test/styles/'; - let file_ambig = load(styles_dir + 'ambig.play'); - let file_example = load(styles_dir + 'example.play'); - - /** - * Parser smoketest: try parsing an old/modified version of the swing style - * (this is the file I add new features to when I'm modifying the grammar) - */ - file_example.then(parser.parse).then(ast => { - ast.init() - // assert.ok(ast.tracks[0] typeof Track); - }); - - /** test for grammar ambiguities with: - * - "|" and "&"-separated lists - * - whitespace-separated lists - * - multiple lines of // comments - */ - file_ambig - .then(parser.string_to_ast) - .then(results => { - assert.equal(results.length, 1, 'expected 1 parse (grammar ambiguous)'); - }); -}; diff --git a/src/index.js b/src/playback.ts similarity index 68% rename from src/index.js rename to src/playback.ts index b02e4a2..de6c6e5 100644 --- a/src/index.js +++ b/src/playback.ts @@ -1,4 +1,4 @@ //import {load} from './loader/loader.js'; //import {parse} from './parser/parser.js'; -export { default as PlaybackStyle } from './PlaybackStyle/PlaybackStyle.js'; -export { default as Player } from './Player/Player.js'; +export { default as PlaybackStyle } from './PlaybackStyle/PlaybackStyle'; +export { default as Player } from './Player/Player'; diff --git a/test/index.html b/test/index.html deleted file mode 100644 index 30d91a0..0000000 --- a/test/index.html +++ /dev/null @@ -1,66 +0,0 @@ - - - Playback Browser Test - - - - - - \ No newline at end of file diff --git a/test/parser.ts b/test/parser.ts new file mode 100644 index 0000000..0ca970f --- /dev/null +++ b/test/parser.ts @@ -0,0 +1,73 @@ +import {} from 'mocha'; +import { expect } from 'chai'; +import * as fs from 'fs'; +import {promisify} from 'util'; + +import * as parser from '../src/parser/parser'; + +const readFile = promisify(fs.readFile); + +// const readFile = (path) => new Promise((r, s) => fs.readFile(path, (err, data) => err ? s(err) : r(data))); + +describe('Parser suite', async () => { + let exampleFile = String(await readFile('./styles/example.play')); + + it('Parser smoketest: parser works with latest grammar features', async (done) => { + const ast1 = await parser.parse(exampleFile); + ast1.init(); + //assert.ok(ast1.tracks[0] typeof Track) + done(); + }) + describe.skip('Grammar ambiguities', () => { + it('"&"-separated lists are unambiguous', async (done) => { + const file = ` + @track "p" as d { + @pattern b { + @pattern(a) & @pattern(a) & @pattern(a) & + @pattern(a) & @pattern(a) & @pattern(a) + } + }`; + const parses = await parser.getPossibleParses(file); + expect(parses).to.have.lengthOf(1); + done(); + }); + + it('"|"-separated lists are unambiguous', async (done) => { + const file = ` + @track "p" as d { + @pattern b { + < 1 | 2 | 3 | 4 | 5 | 6 > + } + }`; + const parses = await parser.getPossibleParses(file); + expect(parses).to.have.lengthOf(1); + done(); + }); + + it('whitespace-separated lists are unambiguous', async (done) => { + const file = ` + @track "p" as d { + @pattern b { + <1> <1> <1> <1> <1> + } + }`; + const parses = await parser.getPossibleParses(file); + expect(parses).to.have.lengthOf(1); + done(); + }); + + it('consecutive line comments are unambiguous', async (done) => { + const file = ` + @track "p" as d { + @pattern b { + // comment 1 + // comment 2 + // comment 3 + } + }`; + const parses = await parser.getPossibleParses(file); + expect(parses).to.have.lengthOf(1); + done(); + }); + }); +}); diff --git a/test/test.bundle.js b/test/test.bundle.js deleted file mode 100644 index 68a9075..0000000 --- a/test/test.bundle.js +++ /dev/null @@ -1,494 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // object to store loaded chunks -/******/ // "0" means "already loaded" -/******/ var installedChunks = { -/******/ "main": 0 -/******/ }; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // uncaught error handler for webpack runtime -/******/ __webpack_require__.oe = function(err) { -/******/ process.nextTick(function() { -/******/ throw err; // catch this error by using import().catch() -/******/ }); -/******/ }; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = "./test/test.js"); -/******/ }) -/************************************************************************/ -/******/ ({ - -/***/ "./node_modules/webpack/buildin/amd-options.js": -/*!****************************************!*\ - !*** (webpack)/buildin/amd-options.js ***! - \****************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("/* WEBPACK VAR INJECTION */(function(__webpack_amd_options__) {/* globals __webpack_amd_options__ */\r\nmodule.exports = __webpack_amd_options__;\r\n\n/* WEBPACK VAR INJECTION */}.call(this, {}))\n\n//# sourceURL=webpack:///(webpack)/buildin/amd-options.js?"); - -/***/ }), - -/***/ "./src/MIDI/Note.js": -/*!**************************!*\ - !*** ./src/MIDI/Note.js ***! - \**************************/ -/*! exports provided: AwaitingDrum, Note, NoteSet */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AwaitingDrum\", function() { return AwaitingDrum; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Note\", function() { return Note; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NoteSet\", function() { return NoteSet; });\n/* harmony import */ var _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../lib/tonal.min.js */ \"./src/lib/tonal.min.js\");\n/* harmony import */ var _drums_json_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./drums.json.js */ \"./src/MIDI/drums.json.js\");\n\n\n\n/**\n * There are some inconsistencies with the official MIDI drum names, this\n * transformation will hopefully ease the pain there.\n * Note: What's the more general word for case-folding? Just \"normalizing\"? Eh\n * @param {string} name\n * @return {string}\n */\nfunction normalizeDrumName(name) {\n return name.toLowerCase().replace(/ |-|_/g, ' ');\n}\n\n// make a map of drum names, which is the inverse of the given JSON file\nlet DRUM_MAP = new Map();\nfor(let midi in _drums_json_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"]) {\n let name = normalizeDrumName(_drums_json_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"][midi])\n DRUM_MAP.set(name, midi);\n}\n\n/**\n * Special pitch value meaning the note will be set later by a DrumBeatGroup\n */\nlet AwaitingDrum = Symbol('AwaitingDrum');\n\n\nclass Note {\n /**\n * @param {Object} opts Options object.\n * @param {number} opts.time The note's time, in beats.\n * @param {string} opts.pitch A string representing the pitch and octave of the note. e.x. 'A4'\n * @param {number} opts.duraion The note's duration, in beats.\n * @param {number} opts.volume The note's volume, as a float 0-1 (inclusive).\n */\n constructor(opts) {\n /**\n * The note's time, in beats.\n * @type {number}\n */\n this.time = opts.time;\n /**\n * A string representing the pitch and octave of the note.\n * @type {string}\n * @example 'A4'\n */\n this.pitch = opts.pitch;\n /**\n * The note's duration, in beats.\n * @type {number}\n */\n this.duration = opts.duration;\n /**\n * The note's volume, as a float 0-1 (inclusive).\n * @type {number}\n */\n this.volume = opts.volume;\n }\n /**\n * An integer representing the MIDI pitch value of the note.\n * @type {number}\n */\n get midi() {\n if(this.pitch === AwaitingDrum) {\n return null;\n } else {\n let drumValue = DRUM_MAP.get(normalizeDrumName(this.pitch));\n if(drumValue) {\n return drumValue;\n } else {\n return _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Note.midi(this.pitch);\n }\n }\n }\n /**\n * An integer 0-127 that roughly correlates to volume\n * @type {number}\n */\n get velocity() {\n return Math.floor(this.volume * 127);\n }\n}\n\nclass NoteSet extends Array {\n constructor() {\n super();\n this.push(...arguments);\n }\n}\n\n\n//# sourceURL=webpack:///./src/MIDI/Note.js?"); - -/***/ }), - -/***/ "./src/MIDI/drums.json.js": -/*!********************************!*\ - !*** ./src/MIDI/drums.json.js ***! - \********************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n \"26\": \"Silence\",\n \"27\": \"High-Q\",\n \"28\": \"Slap\",\n \"29\": \"Scratch Push\",\n \"30\": \"Scratch Pull\",\n \"31\": \"Sticks\",\n \"32\": \"Square Click\",\n \"33\": \"Metronome Click\",\n \"34\": \"Metronome Bell\",\n \"35\": \"Acoustic Bass Drum\",\n \"36\": \"Bass Drum\",\n \"37\": \"Side Stick\",\n \"38\": \"Acoustic Snare\",\n \"39\": \"Hand Clap\",\n \"40\": \"Electric Snare\",\n \"41\": \"Low Floor Tom\",\n \"42\": \"Closed Hi Hat\",\n \"43\": \"High Floor Tom\",\n \"44\": \"Pedal Hi-Hat\",\n \"45\": \"Low Tom\",\n \"46\": \"Open Hi-Hat\",\n \"47\": \"Low-Mid Tom\",\n \"48\": \"Hi-Mid Tom\",\n \"49\": \"Crash Cymbal 1\",\n \"50\": \"High Tom\",\n \"51\": \"Ride Cymbal 1\",\n \"52\": \"Chinese Cymbal\",\n \"53\": \"Ride Bell\",\n \"54\": \"Tambourine\",\n \"55\": \"Splash Cymbal\",\n \"56\": \"Cowbell\",\n \"57\": \"Crash Cymbal 2\",\n \"58\": \"Vibraslap\",\n \"59\": \"Ride Cymbal 2\",\n \"60\": \"Hi Bongo\",\n \"61\": \"Low Bongo\",\n \"62\": \"Mute Hi Conga\",\n \"63\": \"Open Hi Conga\",\n \"64\": \"Low Conga\",\n \"65\": \"High Timbale\",\n \"66\": \"Low Timbale\",\n \"67\": \"High Agogo\",\n \"68\": \"Low Agogo\",\n \"69\": \"Cabasa\",\n \"70\": \"Maracas\",\n \"71\": \"Short Whistle\",\n \"72\": \"Long Whistle\",\n \"73\": \"Short Guiro\",\n \"74\": \"Long Guiro\",\n \"75\": \"Claves\",\n \"76\": \"Hi Wood Block\",\n \"77\": \"Low Wood Block\",\n \"78\": \"Mute Cuica\",\n \"79\": \"Open Cuica\",\n \"80\": \"Mute Triangle\",\n \"81\": \"Open Triangle\",\n \"82\": \"Shaker\",\n \"83\": \"Jingle Bell\",\n \"84\": \"Bell Tree\",\n \"85\": \"Castanets\",\n \"86\": \"Mute Surdo\",\n \"87\": \"Open Surdo\"\n});\n\n\n//# sourceURL=webpack:///./src/MIDI/drums.json.js?"); - -/***/ }), - -/***/ "./src/PlaybackStyle/PlaybackStyle.js": -/*!********************************************!*\ - !*** ./src/PlaybackStyle/PlaybackStyle.js ***! - \********************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return PlaybackStyle; });\n/* harmony import */ var _loader_loader_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../loader/loader.js */ \"./src/loader/loader-node.js\");\n/* harmony import */ var _parser_parser_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../parser/parser.js */ \"./src/parser/parser.js\");\n/* harmony import */ var _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../MIDI/Note.js */ \"./src/MIDI/Note.js\");\n\n\n\n\nclass PlaybackStyle {\n /**\n * Set the main ast (the one that plays all its instruments by default).\n * @param {ast.GlobalScope} main the main ast\n * @param {Map.} asts A map of asts by their path\n */\n constructor(mainPath) {\n this._mainPath = mainPath;\n this._ASTs = new Map();\n this._initialized = false;\n }\n /**\n * Parse each file, pull its dependencies, put it all in a cache, rinse and\n * repeat.\n * @private\n */\n async _loadDependencies() {\n let pendingDependencies = [this._mainPath];\n let dependencyPath;\n // @TODO: verify that dependencies have compatible time signature to main\n while(dependencyPath = pendingDependencies.pop()) {\n let rawfile;\n try {\n rawfile = await Object(_loader_loader_js__WEBPACK_IMPORTED_MODULE_0__[\"load\"])(dependencyPath);\n } catch(e) {\n throw new Error(`Couldn't locate imported style \"${dependencyPath}\".`);\n }\n let ast = await Object(_parser_parser_js__WEBPACK_IMPORTED_MODULE_1__[\"parse\"])(rawfile);\n this._ASTs.set(dependencyPath, ast);\n ast.init();\n for(let newDependency of ast.dependencies) {\n if(!this._ASTs.has(newDependency)) {\n pendingDependencies.push(newDependency);\n }\n }\n }\n this._main = this._ASTs.get(this._mainPath);\n }\n _link() {\n this._main.link(this._ASTs);\n }\n /**\n * Initialize the style, which includes loading dependencies and linking\n * track/pattern calls. Must be called before compiling/playing.\n */\n async init() {\n await this._loadDependencies();\n this._link();\n this._initialized = true;\n }\n /**\n * Compile a song into a set of MIDI-like note instructions.\n * @param {Song} song A Playback Song (notochord????)\n * @returns {NoteSet.} An array-like object containing MIDI-like note\n * instructions.\n */\n compile(song) {\n if(!this._initialized) {\n throw new Error('PlayBack style must be initialized before compiling');\n }\n let songIterator = song[Symbol.iterator]();\n let instruments = this.getInstruments();\n let notes = new Map();\n let beatsPerMeasure = this._main.vars.get('time-signature')[0];\n let totalPastBeats = 0;\n for(let instrument of instruments) notes.set(instrument, new _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_2__[\"NoteSet\"]());\n let nextValue;\n while(nextValue = songIterator.next(), nextValue.done == false) {\n let thisMeasureTracks = this._main.execute(songIterator);\n for(let [instrument, thisMeasureNotes] of thisMeasureTracks) {\n for(let note of thisMeasureNotes) {\n note.time += totalPastBeats;\n if(this._main.vars.get('swing')) {\n let int_part = Math.floor(note.time);\n let float_part = note.time - int_part;\n if(float_part <= 0.5) {\n float_part *= 2;\n float_part = (2/3) * float_part;\n } else {\n float_part = 2 * (float_part - 0.5);\n float_part = (2/3) + ((1/3) * float_part);\n }\n note.time = int_part + float_part;\n }\n }\n notes.get(instrument).push(...thisMeasureNotes);\n }\n totalPastBeats += beatsPerMeasure;\n }\n \n return notes;\n }\n getInstruments() {\n return this._main.getInstruments();\n }\n}\n\n\n//# sourceURL=webpack:///./src/PlaybackStyle/PlaybackStyle.js?"); - -/***/ }), - -/***/ "./src/Player/Player.js": -/*!******************************!*\ - !*** ./src/Player/Player.js ***! - \******************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return Player; });\n/* harmony import */ var _lib_soundfont_player_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../lib/soundfont-player.js */ \"./src/lib/soundfont-player.js\");\n\n\nclass Player {\n /**\n * Loads the necessary soundfonts and plays a song in a PlaybackStyle in the\n * browser.\n * @param {AudioContext=} context If you pass it an AudioContext it'll use\n * it. Otherwise it'll make its own.\n */\n constructor(context) {\n this._style = null;\n this.context = context || new AudioContext({latencyHint: \"playback\"});\n this._initialized = false;\n window.player = this;\n }\n async setStyle(style) {\n this._style = style;\n if(!style._initialized) {\n await style.init();\n }\n this._initialized = false;\n this.soundfonts = new Map();\n let promises = [];\n for(let instrument of style.getInstruments()) {\n let sfpromise;\n if(instrument.startsWith('http://') || instrument.startsWith('https://')) {\n // Soundfont has a bug where you can't just pass it a URL\n // @TODO: open an issue there\n sfpromise = _lib_soundfont_player_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].instrument(this.context, instrument, {\n isSoundfontUrl: () => true,\n nameToUrl: () => url\n });\n } else if(instrument == 'percussion') {\n sfpromise = _lib_soundfont_player_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].instrument(this.context, instrument, {soundfont: 'FluidR3_GM'});\n } else {\n sfpromise = _lib_soundfont_player_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].instrument(this.context, instrument);\n }\n promises.push(\n await sfpromise.then(font => {\n this.soundfonts.set(instrument, font);\n })\n );\n }\n await Promise.all(promises);\n this._initialized = true;\n }\n play(song) {\n if(!this._style) {\n throw new Error('No style selected');\n }\n if(!this._initialized) {\n throw new Error('A style hasn\\'t finished loading');\n }\n\n if(this.context.state == 'suspended') {\n this.context.resume();\n }\n\n let compiledSong = this._style.compile(song);\n\n let tempoCoef = 0.4; // WHATEVER IDC HOW ANYTHING WORKS\n let startTime = this.context.currentTime + 1;\n for(let [instrument, notes] of compiledSong) {\n let soundfont = this.soundfonts.get(instrument);\n for(let note of notes) {\n let start = startTime + (tempoCoef * note.time);\n let dur = tempoCoef * note.duration - 0.05;\n soundfont.play(note.midi, start, {\n duration: dur,\n gain: note.volume\n })\n }\n }\n }\n}\n\n//# sourceURL=webpack:///./src/Player/Player.js?"); - -/***/ }), - -/***/ "./src/ast/ArgumentOperators.js": -/*!**************************************!*\ - !*** ./src/ast/ArgumentOperators.js ***! - \**************************************/ -/*! exports provided: AnchorArgument, BooleanNot, BooleanAnd, BooleanOr */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AnchorArgument\", function() { return AnchorArgument; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"BooleanNot\", function() { return BooleanNot; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"BooleanAnd\", function() { return BooleanAnd; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"BooleanOr\", function() { return BooleanOr; });\n/* harmony import */ var _type_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./type_utils.js */ \"./src/ast/type_utils.js\");\n\n\nclass AnchorArgument {\n constructor(anchor) {\n this.anchor = anchor;\n }\n}\n\nclass BooleanOperator {\n constructor() {\n this.args = [...arguments];\n }\n link(ASTs, parentStyle, parentTrack) {\n this.args.forEach(arg => {\n if(arg.link) arg.link(ASTs, parentStyle, parentTrack);\n });\n }\n init(scope) {\n this.scope = scope\n this.args.forEach(arg => {\n if(arg.init) arg.init(scope);\n });\n }\n resolve_args(songIterator) {\n return this.args.map(arg => {\n if(arg.execute) {\n return arg.execute(songIterator);\n } else {\n return arg;\n }\n });\n }\n}\n\nclass BooleanNot extends BooleanOperator {\n constructor() {\n super(...arguments);\n }\n execute(songIterator) {\n let args = this.resolve_args(songIterator);\n return !Object(_type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"cast_bool\"])(args[0]);\n }\n}\nclass BooleanAnd extends BooleanOperator {\n constructor() {\n super(...arguments);\n }\n execute(songIterator) {\n // sorry no short-circuiting because this code is prettier\n // @TODO: add short-circuiting if this actually makes it too slow\n let args = this.resolve_args(songIterator);\n return Object(_type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"cast_bool\"])(args[0]) && Object(_type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"cast_bool\"])(args[1]);\n }\n}\nclass BooleanOr extends BooleanOperator {\n constructor() {\n super(...arguments);\n }\n execute(songIterator) {\n let args = this.resolve_args(songIterator);\n return Object(_type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"cast_bool\"])(args[0]) || Object(_type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"cast_bool\"])(args[1]);\n }\n}\n\n\n//# sourceURL=webpack:///./src/ast/ArgumentOperators.js?"); - -/***/ }), - -/***/ "./src/ast/BeatGroups.js": -/*!*******************************!*\ - !*** ./src/ast/BeatGroups.js ***! - \*******************************/ -/*! exports provided: BeatGroupLiteral, Measure, DrumBeatGroupLiteral */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"BeatGroupLiteral\", function() { return BeatGroupLiteral; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Measure\", function() { return Measure; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"DrumBeatGroupLiteral\", function() { return DrumBeatGroupLiteral; });\n/* harmony import */ var _errors_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./errors.js */ \"./src/ast/errors.js\");\n/* harmony import */ var _type_utils_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./type_utils.js */ \"./src/ast/type_utils.js\");\n/* harmony import */ var _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../MIDI/Note.js */ \"./src/MIDI/Note.js\");\n/* harmony import */ var _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./BeatLiterals.js */ \"./src/ast/BeatLiterals.js\");\n/* harmony import */ var _FunctionCall_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./FunctionCall.js */ \"./src/ast/FunctionCall.js\");\n\n\n\n\n\n\nclass BeatGroupLiteral {\n constructor(measures) {\n this.measures = measures;\n this.scope = null;\n }\n init(scope) {\n this.scope = scope;\n this.measures.forEach((measure, i) => measure.init(scope, this, i));\n }\n link() {return;}\n execute(songIterator) {\n let joinedMeasures = new _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_2__[\"NoteSet\"]();\n for(let i = 0; i < this.measures.length; i++) {\n let offset = i * 4; // @TODO: pull in actual meter somehow\n let measureNotes = this.measures[i].execute(songIterator);\n if(measureNotes === _type_utils_js__WEBPACK_IMPORTED_MODULE_1__[\"Nil\"]) return _type_utils_js__WEBPACK_IMPORTED_MODULE_1__[\"Nil\"]; // lets a/s abort the beatgroup\n for(let measureNote of measureNotes) {\n measureNote.time += offset;\n joinedMeasures.push(measureNote);\n }\n }\n return joinedMeasures;\n }\n getNextStaticBeatRoot(measureIndex, beatIndex, songIterator) {\n // first, try every subsequent beat in the beatGroup\n // (including subsequent measures)\n let measure, beat;\n while(measure = this.parentBeatGroup.measures[measureIndex++]) {\n while(beat = measure.beats[++beatIndex]) {\n if(!beat.isDynamic()) {\n return beat.getAnchorData(songIterator)[1];\n }\n }\n beatIndex = -1;\n }\n // if there are no non-dynamic beats in the rest of the beat-group, return\n // the first note of the next measure (@TODO: could be multiple measures\n // later if it's a multi-measure beatgroup)\n // @TODO: wtf?\n return _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_3__[\"MelodicBeatLiteral\"].normalizeChord(songIterator.getRelative(1)[0]);\n }\n}\n\nclass Measure {\n constructor(beats) {\n this.beats = beats;\n this.beatsPerMeasure = null;\n this.scope = null;\n }\n calculateDurationAfter(beatIndex) {\n let currentBeat = this.beats[beatIndex];\n let currentBeatTime = currentBeat.getTime();\n \n let nextBeatTime;\n if(beatIndex + 1 >= this.beats.length) {\n nextBeatTime = this.beatsPerMeasure + 1;\n } else {\n let nextBeat = this.beats[beatIndex + 1];\n nextBeatTime = nextBeat.getTime();\n }\n return nextBeatTime - currentBeatTime;\n }\n getNextStaticBeatRoot(beatIndex, songIterator) {\n return this.parentBeatGroup.getNextStaticBeatRoot(\n this.indexInBeatGroup,\n beatIndex,\n songIterator\n );\n }\n init(scope, parentBeatGroup, indexInBeatGroup) {\n this.scope = scope;\n this.parentBeatGroup = parentBeatGroup;\n this.indexInBeatGroup = indexInBeatGroup;\n this.beatsPerMeasure = this.scope.vars.get('time-signature')[0];\n // @TODO does this need more math?\n this.beats.forEach((beat, i) => {\n beat.init(scope, this, i);\n });\n }\n execute(songIterator) {\n // clear cached notes (used for STEP/ARPEGGIATE interpolation)\n for(let beat of this.beats) {\n beat.cachedAnchor = null;\n }\n // each beat returns a NoteSet since it could be a chord or whatever\n let joined = new _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_2__[\"NoteSet\"]();\n for(let beat of this.beats) {\n let notes = beat.execute(songIterator);\n if(notes === _type_utils_js__WEBPACK_IMPORTED_MODULE_1__[\"Nil\"]) return _type_utils_js__WEBPACK_IMPORTED_MODULE_1__[\"Nil\"]; // lets a and s abort the beatgroup.\n joined.push(...notes);\n }\n return joined;\n }\n}\n\nclass DrumBeatGroupLiteral {\n constructor(drum, beatGroup) {\n this.drum = drum;\n this.beatGroup = beatGroup; // for now there's no diff in functionality...\n // @TODO make sure our beats are all drummy\n }\n init(scope) {\n this.scope = scope;\n if(this.beatGroup.init) this.beatGroup.init(scope);\n }\n link() {return;} // @TODO: I think patterncalls are allowed here?\n execute(songIterator) {\n let notes = this.beatGroup.execute(songIterator);\n for(let note of notes) {\n if(note.pitch === _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_2__[\"AwaitingDrum\"]) {\n note.pitch = this.drum; // @TODO: convert to number?\n } else {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_0__[\"MelodicBeatInDrumBeatGroupError\"](this.scope);\n }\n }\n return notes;\n }\n}\n\n\n//# sourceURL=webpack:///./src/ast/BeatGroups.js?"); - -/***/ }), - -/***/ "./src/ast/BeatLiterals.js": -/*!*********************************!*\ - !*** ./src/ast/BeatLiterals.js ***! - \*********************************/ -/*! exports provided: MelodicBeatLiteral, DrumBeatLiteral */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MelodicBeatLiteral\", function() { return MelodicBeatLiteral; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"DrumBeatLiteral\", function() { return DrumBeatLiteral; });\n/* harmony import */ var _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../lib/tonal.min.js */ \"./src/lib/tonal.min.js\");\n/* harmony import */ var _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../MIDI/Note.js */ \"./src/MIDI/Note.js\");\n//import {Nil} from './type_utils.js';\n\n\n\nclass MelodicBeatLiteral {\n constructor(opts) {\n this.time = opts.time || {time: 'auto'};\n this.pitch = opts.pitch;\n this.octave = opts.octave || 'inherit';\n this.scope = null;\n this.parentMeasure = null;\n this.indexInMeasure = null;\n this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation\n }\n init(scope, parentMeasure, indexInMeasure) {\n this.scope = scope;\n this.parentMeasure = parentMeasure;\n this.indexInMeasure = indexInMeasure;\n }\n getTime() {\n if(this.time.time === 'auto') {\n return this.indexInMeasure + 1;\n } else {\n return this.time.time;\n }\n }\n /**\n * Normalize a chord into a form tonal can handle\n * @param {string} chord\n * @return {string}\n */\n static normalizeChord(chord) {\n return chord\n .replace(/-/g, '_') // tonal uses _ over - for minor7\n .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords??\n }\n static chordToScaleName(chord) {\n let chordType = _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Chord.tokenize(chord)[1];\n\n // @TODO: make this more robust\n let names = _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Chord.props(chordType).names;\n if(names.includes('dim')) return 'diminished';\n if(names.includes('aug')) return 'augmented';\n if(names.includes('Major')) return 'major';\n if(names.includes('minor')) return 'minor';\n if(names.includes('minor7')) return 'dorian';\n if(names.includes('Dominant')) return 'mixolydian';\n // if none of the above match, do our best to find the closest fit\n let closestScale = 'major'\n names.forEach(name => {\n if(name.startsWith('dim')) closestScale = 'diminished';\n if(name.startsWith('aug')) closestScale = 'augmented';\n if(name.startsWith('M')) closestScale = 'major';\n if(name.startsWith('m')) closestScale = 'minor';\n });\n return closestScale;\n }\n handleInversion(songIterator, pitches) {\n let tonicPC = songIterator.song.getKey();\n let tonicNote = _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Note.from({oct: this.getOctave()}, tonicPC);\n let tonic = _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Note.midi(tonicNote);\n let outPitches = [];\n for(let pitchNote of pitches) {\n let pitch = _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Note.midi(pitchNote);\n if(pitch - tonic >= 6) pitch -= 12;\n outPitches.push(_lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Note.fromMidi(pitch));\n }\n return outPitches;\n }\n static getAnchorChord(anchor, songIterator, currentTime) {\n let anchorChord;\n switch(anchor) {\n case 'KEY': {\n anchorChord = songIterator.song.getKey();\n }\n case 'NEXT': {\n let nextMeasure = songIterator.getRelative(1);\n if(nextMeasure) {\n anchorChord = nextMeasure[0];\n } else {\n anchorChord = songIterator.song.getKey();\n }\n }\n case 'STEP':\n case 'ARPEGGIATE': {\n let prev = songIterator.getRelative(0)[0]; //???\n let next = this.parentMeasure.getNextStaticBeatRoot(\n this.indexInMeasure,\n songIterator\n );\n\n }\n default: {\n // crawl backward through this measure to get the last set beat\n let lastSetBeat = Math.floor(currentTime);\n let iteratorMeasure = songIterator.getRelative(0);\n do {\n anchorChord = iteratorMeasure[lastSetBeat];\n lastSetBeat--;\n } while(!anchorChord);\n }\n }\n return this.normalizeChord(anchorChord);\n }\n static anchorChordToRoot(anchorChord, degree, octave) {\n let anchorTonic = _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Chord.tokenize(anchorChord)[0];\n let anchorScaleName = this.chordToScaleName(anchorChord);\n let scalePCs = _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Scale.notes(anchorTonic, anchorScaleName);\n let rootPC = scalePCs[degree - 1];\n return _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Note.from({oct: octave}, rootPC);\n }\n getAnchorData(songIterator) {\n let anchorChord = this.constructor.getAnchorChord(\n this.pitch.anchor, songIterator, this.getTime()\n );\n\n let root = this.constructor.anchorChordToRoot(\n anchorChord, this.pitch.degree, this.getOctave()\n );\n return [anchorChord, root];\n }\n getPitches(songIterator) {\n let [anchorChord, root] = this.getAnchorData(songIterator);\n\n let pitches;\n if(this.pitch.chord) {\n // this feels extremely incorrect\n // why would anyone need it to work this way\n let anchorChordType = _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Chord.tokenize(anchorChord)[1];\n pitches = _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Chord.notes(root, anchorChordType);\n } else {\n pitches = [root];\n }\n\n if(this.scope.vars.get('invertible')) {\n pitches = this.handleInversion(songIterator, pitches);\n }\n\n return pitches;\n }\n /**\n * Returns true if the beat is anchored via STEP or ARPEGGIATE\n * @returns {boolean}\n */\n isDynamic() {\n return ['STEP', 'ARPEGGIATE'].includes(this.pitch.anchor);\n }\n getOctave() {\n if(this.octave === 'inherit') {\n return this.scope.vars.get('octave');\n } else {\n return this.octave;\n }\n }\n getDuration() {\n let duration;\n duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure);\n if(this.time.flag === 'STACCATO') {\n return Math.min(0.25, duration);\n } else {\n return duration;\n }\n }\n getVolume() {\n let volume = this.scope.vars.get('volume');\n if(this.time.flag === 'ACCENTED') volume = Math.min(1, volume += .1);\n return volume;\n }\n execute(songIterator) {\n let notes = new _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__[\"NoteSet\"]();\n let time = this.getTime(); // @TODO: this varies with rolling\n let pitches = this.getPitches(songIterator);\n let duration = this.getDuration(); // @TODO: this varies with rolling\n let volume = this.getVolume();\n \n for(let pitch of pitches) {\n notes.push(new _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__[\"Note\"]({\n time: time,\n pitch: pitch,\n duration: duration,\n volume: volume\n }));\n }\n \n return notes;\n }\n}\n\nclass DrumBeatLiteral {\n constructor(opts) {\n this.time = opts.time;\n this.accented = opts.accented || false;\n this.scope = null;\n this.parentMeasure = null;\n this.indexInMeasure = null;\n }\n init(scope, parentMeasure, indexInMeasure) {\n this.scope = scope;\n this.parentMeasure = parentMeasure;\n this.indexInMeasure = indexInMeasure;\n }\n getTime() {\n return this.time;\n }\n getDuration() {\n let duration;\n duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure);\n return duration;\n }\n getVolume() {\n let volume = this.scope.vars.get('volume');\n if(this.accented) volume = Math.min(1, volume += .1);\n return volume;\n }\n execute(songIterator) {\n let time = this.getTime();\n let duration = this.getDuration();\n let volume = this.getVolume();\n \n return new _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__[\"NoteSet\"](\n new _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__[\"Note\"]({\n time: time,\n pitch: _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__[\"AwaitingDrum\"],\n duration: duration,\n volume: volume\n })\n );\n }\n}\n\n\n//# sourceURL=webpack:///./src/ast/BeatLiterals.js?"); - -/***/ }), - -/***/ "./src/ast/ConfigStatements.js": -/*!*************************************!*\ - !*** ./src/ast/ConfigStatements.js ***! - \*************************************/ -/*! exports provided: MetaStatement, OptionsStatement, ImportStatement */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MetaStatement\", function() { return MetaStatement; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"OptionsStatement\", function() { return OptionsStatement; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ImportStatement\", function() { return ImportStatement; });\n/* harmony import */ var _Scope_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Scope.js */ \"./src/ast/Scope.js\");\n\n\nclass MetaStatement extends _Scope_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor(function_calls) {\n super();\n this.name = '@meta';\n this.type = '@meta';\n this.function_calls = function_calls;\n }\n init(scope) {\n this.scope = scope;\n \n // nothing in here can be dynamic so resolve these at compile time\n for(let function_call of this.function_calls) {\n function_call.init(this);\n function_call.execute();\n }\n \n scope.meta = this.vars;\n }\n}\n\nclass OptionsStatement extends _Scope_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor(function_calls) {\n super();\n this.name = '@options';\n this.type = '@options';\n this.function_calls = function_calls;\n }\n init(scope) {\n \n // nothing in here /should/ be dynamic so resolve these at compile time\n for(let function_call of this.function_calls) {\n function_call.init(this);\n function_call.execute();\n }\n \n this.scope = scope;\n // in this case we're actually overwriting our scope's variables, not\n // vise-versa\n scope.vars = new Map([...scope.vars, ...this.vars]);\n }\n}\n\nclass ImportStatement {\n constructor(path, identifier) {\n this.path = path;\n this.identifier = identifier;\n }\n}\n\n\n//# sourceURL=webpack:///./src/ast/ConfigStatements.js?"); - -/***/ }), - -/***/ "./src/ast/FunctionCall.js": -/*!*********************************!*\ - !*** ./src/ast/FunctionCall.js ***! - \*********************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return FunctionCall; });\n/* harmony import */ var _function_data_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./function_data.js */ \"./src/ast/function_data.js\");\n/* harmony import */ var _errors_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./errors.js */ \"./src/ast/errors.js\");\n\n\n\n/**\n * If the value is a FunctionCall, call it and return the returned value.\n * Otherwise, return the value itself.\n * @private\n */ // @TODO: if this is needed elsewhere, put it somewhere useful.\n\nclass FunctionCall {\n /**\n * @constructor\n * @param {string} identifier The name of the function. Ideally it should\n * match the name of one of the functions in function_data.js\n */\n constructor(identifier, args) {\n this.identifier = identifier;\n this.definition = _function_data_js__WEBPACK_IMPORTED_MODULE_0__[\"definitions\"].get(identifier);\n this.args = args;\n this.scope = null;\n }\n init(scope) {\n this.scope = scope;\n if(!this.definition) {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_1__[\"FunctionNameError\"](this.identifier, this.scope);\n }\n this.returns = this.definition.returns;\n _function_data_js__WEBPACK_IMPORTED_MODULE_0__[\"assertScope\"](this.identifier, this.definition.scope, this.scope);\n \n this.args.forEach(arg => {\n if(arg.init) arg.init(scope);\n });\n \n _function_data_js__WEBPACK_IMPORTED_MODULE_0__[\"assertArgTypes\"](this.identifier, this.args, this.definition.types, this.scope);\n }\n link(ASTs, parentStyle, parentTrack) {\n this.args.forEach(arg => {\n if(arg.link) arg.link(ASTs, parentStyle, parentTrack);\n });\n }\n execute(songIterator) {\n if(!this.scope) throw new Error('function not initialized :(');\n let evaluated_args = this.args.map(arg => {\n if(arg.execute) {\n return arg.execute(songIterator);\n } else {\n return arg;\n }\n });\n let return_value = this.definition.execute(\n evaluated_args,\n songIterator,\n this.scope);\n if(return_value === undefined) {\n throw new Error(`Function \"${this.identifier}\" can return undefined`);\n }\n return return_value;\n }\n}\n\n\n//# sourceURL=webpack:///./src/ast/FunctionCall.js?"); - -/***/ }), - -/***/ "./src/ast/GlobalScope.js": -/*!********************************!*\ - !*** ./src/ast/GlobalScope.js ***! - \********************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return GlobalScope; });\n/* harmony import */ var _type_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./type_utils.js */ \"./src/ast/type_utils.js\");\n/* harmony import */ var _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../MIDI/Note.js */ \"./src/MIDI/Note.js\");\n/* harmony import */ var _errors_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./errors.js */ \"./src/ast/errors.js\");\n/* harmony import */ var _Scope_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Scope.js */ \"./src/ast/Scope.js\");\n/* harmony import */ var _ConfigStatements_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./ConfigStatements.js */ \"./src/ast/ConfigStatements.js\");\n/* harmony import */ var _Track_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Track.js */ \"./src/ast/Track.js\");\n\n\n\n\n\n\n\nclass GlobalScope extends _Scope_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"] {\n constructor(statements) {\n super();\n \n this.name = 'global';\n this.type = 'global';\n \n this.statements = statements;\n }\n \n init() {\n // set some default values\n this.vars.set('time-signature', [4, 4]);\n this.vars.set('tempo', 120);\n \n this.tracks = new Map();\n this.meta = [];\n // @TODO: stop circular dependencies? cache them and mark one as mom\n this.importedStyles = new Map();\n this.trackCalls = [];\n this.dependencies = [];\n \n for(let statement of this.statements) {\n if(statement instanceof _ConfigStatements_js__WEBPACK_IMPORTED_MODULE_4__[\"MetaStatement\"]\n || statement instanceof _ConfigStatements_js__WEBPACK_IMPORTED_MODULE_4__[\"OptionsStatement\"]) {\n // @TODO: make sure there's exactly 1 meta block\n this.meta.push(statement);\n } else if(statement instanceof _ConfigStatements_js__WEBPACK_IMPORTED_MODULE_4__[\"ImportStatement\"]) {\n this.importedStyles.set(statement.identifier, statement.path);\n this.dependencies.push(statement.path);\n } else if(statement instanceof _Track_js__WEBPACK_IMPORTED_MODULE_5__[\"TrackStatement\"]) {\n this.tracks.set(statement.name, statement);\n } else if(statement instanceof _Track_js__WEBPACK_IMPORTED_MODULE_5__[\"TrackCall\"]) {\n this.trackCalls.push(statement);\n }\n }\n // handle meta blocks first since they set variables in own scope\n this.meta.forEach(statement => statement.init(this));\n \n // -- handle importing before statements --\n \n this.tracks.forEach(statement => statement.init(this));\n }\n link(ASTs) {\n for(let trackCall of this.trackCalls) {\n // get path name of style\n let importPath = this.importedStyles.get(trackCall.import);\n \n let ast = ASTs.get(importPath);\n if(!ast) throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"NoSuchStyleError\"](trackCall.import, this);\n let trackStatement = ast.tracks.get(trackCall.track);\n if(!trackStatement) throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"NoSuchTrackError\"](\n trackCall.import,\n trackCall.track,\n this);\n //trackCall.trackStatement = trackStatement;\n this.tracks.set(`${trackCall.import}.${trackCall.track}`, trackStatement);\n }\n \n for(let [, track] of this.tracks) {\n track.link(ASTs, this);\n }\n }\n execute(songIterator) {\n let trackNoteMap = new Map();\n for(let [, track] of this.tracks) {\n let trackNotes = track.execute(songIterator);\n if(trackNotes !== _type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"Nil\"]) trackNoteMap.set(track.instrument, trackNotes);\n }\n return trackNoteMap;\n }\n getInstruments() {\n let instruments = new Set();\n for(let [, track] of this.tracks) {\n instruments.add(track.instrument);\n }\n return instruments;\n }\n}\n\n\n//# sourceURL=webpack:///./src/ast/GlobalScope.js?"); - -/***/ }), - -/***/ "./src/ast/Pattern.js": -/*!****************************!*\ - !*** ./src/ast/Pattern.js ***! - \****************************/ -/*! exports provided: PatternExpressionGroup, PatternStatement, PatternCall, JoinedPatternExpression */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"PatternExpressionGroup\", function() { return PatternExpressionGroup; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"PatternStatement\", function() { return PatternStatement; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"PatternCall\", function() { return PatternCall; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"JoinedPatternExpression\", function() { return JoinedPatternExpression; });\n/* harmony import */ var _type_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./type_utils.js */ \"./src/ast/type_utils.js\");\n/* harmony import */ var _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../MIDI/Note.js */ \"./src/MIDI/Note.js\");\n/* harmony import */ var _errors_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./errors.js */ \"./src/ast/errors.js\");\n/* harmony import */ var _Scope_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Scope.js */ \"./src/ast/Scope.js\");\n/* harmony import */ var _FunctionCall_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./FunctionCall.js */ \"./src/ast/FunctionCall.js\");\n\n\n\n\n\n\nclass PatternExpressionGroup extends _Scope_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"] {\n constructor(expressions) {\n super();\n this.type = 'PatternExpressionGroup';\n this.name = '@pattern()';\n \n this.defaultVars.set('private', false);\n this.defaultVars.set('chance', 1);\n \n this.expressions = expressions;\n this.function_calls = [];\n this.non_function_call_expressions = [];\n }\n init(scope, patternStatement = null) {\n super.init(scope);\n this.patternStatement = patternStatement;\n if(this.patternStatement) {\n this.name = `@pattern(${this.patternStatement})`;\n }\n this.expressions.forEach(expression => {\n if(expression.init) {\n expression.init(this);\n } else {\n throw ['expression not initialized:', expression];\n }\n if(expression instanceof _FunctionCall_js__WEBPACK_IMPORTED_MODULE_4__[\"default\"]) {\n this.function_calls.push(expression);\n } else {\n this.non_function_call_expressions.push(expression);\n }\n });\n }\n link(ASTs, parentStyle, parentTrack) {\n this.expressions.forEach(expression => {\n expression.link(ASTs, parentStyle, parentTrack);\n });\n }\n execute(songIterator, callerIsTrack = false) {\n this.inherit();\n let beats = _type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"Nil\"];\n for(let function_call of this.function_calls) {\n let return_value = function_call.execute(songIterator);\n if(return_value instanceof _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__[\"NoteSet\"]) {\n if(beats !== _type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"Nil\"]) {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"TooManyBeatsError\"](this);\n }\n beats = return_value;\n }\n }\n if(callerIsTrack && this.vars.get('private') === true) {\n return _type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"Nil\"]; // if it's private we can give up now\n }\n for(let expression of this.non_function_call_expressions) {\n if(expression.execute) {\n expression = expression.execute(songIterator);\n }\n if(expression instanceof _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__[\"NoteSet\"]) {\n if(beats !== _type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"Nil\"]) {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"TooManyBeatsError\"](this);\n }\n beats = expression;\n }\n }\n return beats\n }\n}\n\nclass PatternStatement extends PatternExpressionGroup {\n constructor(opts) {\n if(opts.expression instanceof PatternExpressionGroup) {\n // unroll the redundant expression group\n super(opts.expression.expressions);\n } else {\n super([opts.expression]);\n }\n this.identifier = opts.identifier;\n this.condition = (opts.condition !== undefined) ? opts.condition : null;\n }\n getChance() {\n return this.vars.get('chance');\n }\n link(ASTs, parentStyle, parentTrack) {\n super.link(ASTs, parentStyle, parentTrack);\n if(this.condition && this.condition.link) {\n this.condition.link(ASTs, parentStyle, parentTrack);\n }\n }\n init(scope) {\n super.init(scope);\n if(this.condition && this.condition.init) this.condition.init(this);\n }\n execute(songIterator, callerIsTrack) {\n if(this.condition) {\n let condition_value;\n if(this.condition.execute) {\n condition_value = this.condition.execute(songIterator);\n } else {\n condition_value = this.condition;\n }\n if(Object(_type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"cast_bool\"])(condition_value) === false) return _type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"Nil\"];\n }\n return super.execute(songIterator, callerIsTrack);\n }\n}\n\nclass PatternCall {\n constructor(opts) {\n this.import = opts.import || null;\n this.track = opts.track || null;\n this.pattern = opts.pattern;\n this.scope = null;\n this.patternStatement = null;\n this.prettyprintname = (this.import || 'this') + '.' +\n (this.track || 'this') + '.' +\n this.pattern;\n }\n getChance() {\n return this.patternStatement.getChance()();\n }\n init(scope) {\n this.scope = scope;\n }\n link(ASTs, parentStyle, parentTrack) {\n let ast;\n if(this.import === null) {\n ast = parentStyle\n } else {\n // get path name of style\n let importPath = parentStyle.importedStyles.get(this.import);\n ast = ASTs.get(importPath);\n if(!ast) throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"NoSuchStyleError\"](this.import, this);\n }\n let track;\n if(this.track === null) {\n track = parentTrack;\n } else {\n track = ast.tracks.get(this.track);\n if(!track) throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"NoSuchTrackError\"](\n this.import || 'this',\n this.track || 'this',\n this);\n }\n let patternStatement = track.patterns.get(this.pattern);\n if(!patternStatement) throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"NoSuchPatternError\"](\n this.import || 'this',\n this.track || 'this',\n this.pattern,\n this);\n this.patternStatement = patternStatement;\n }\n execute(songIterator) {\n // called patternStatement ignores private()\n return this.patternStatement.execute(songIterator);\n }\n}\n\nclass JoinedPatternExpression {\n constructor(patterns) {\n this.patterns = patterns;\n }\n init(scope) {\n this.scope = scope;\n this.patterns.forEach(pattern => {\n if(pattern.init) pattern.init(scope);\n });\n }\n link(ASTs, parentStyle, parentTrack) {\n this.patterns.forEach(pattern => {\n pattern.link(ASTs, parentStyle, parentTrack);\n });\n }\n execute(songIterator) {\n let noteSets = [];\n for(let pattern of this.patterns) {\n if(pattern.execute) {\n pattern = pattern.execute(songIterator);\n }\n if(pattern instanceof _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__[\"NoteSet\"]) {\n noteSets.push(pattern);\n }\n }\n if(noteSets.length) {\n return (new _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_1__[\"NoteSet\"]()).concat(...noteSets);\n } else {\n return _type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"Nil\"];\n }\n }\n}\n\n\n//# sourceURL=webpack:///./src/ast/Pattern.js?"); - -/***/ }), - -/***/ "./src/ast/Scope.js": -/*!**************************!*\ - !*** ./src/ast/Scope.js ***! - \**************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return Scope; });\n/*\n * In Playback styles, basically any pair of curly brackets defines a scope\n * which inherits settings from its parent scope but can overwrite them.\n */\nclass Scope {\n constructor() {\n this.defaultVars = new Map();\n this.vars = new Map();\n this.name = null;\n this.type = null;\n this.scope = null;\n }\n inherit() {\n this.vars = new Map([...this.defaultVars, ...this.scope.vars]);\n }\n init(scope) { // parent scope, if that's unclear\n this.scope = scope;\n \n // in case this.vars was set in the constructor\n this.vars = new Map([...this.defaultVars, ...this.scope.vars, ...this.vars]);\n }\n}\n\n\n//# sourceURL=webpack:///./src/ast/Scope.js?"); - -/***/ }), - -/***/ "./src/ast/Track.js": -/*!**************************!*\ - !*** ./src/ast/Track.js ***! - \**************************/ -/*! exports provided: TrackStatement, TrackCall */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"TrackStatement\", function() { return TrackStatement; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"TrackCall\", function() { return TrackCall; });\n/* harmony import */ var _type_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./type_utils.js */ \"./src/ast/type_utils.js\");\n/* harmony import */ var _errors_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./errors.js */ \"./src/ast/errors.js\");\n/* harmony import */ var _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../MIDI/Note.js */ \"./src/MIDI/Note.js\");\n/* harmony import */ var _Scope_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Scope.js */ \"./src/ast/Scope.js\");\n/* harmony import */ var _FunctionCall_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./FunctionCall.js */ \"./src/ast/FunctionCall.js\");\n/* harmony import */ var _Pattern_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Pattern.js */ \"./src/ast/Pattern.js\");\n\n\n\n\n\n\n\nclass TrackStatement extends _Scope_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"] {\n constructor(opts) {\n super();\n this.name = opts.identifier;\n this.type = '@track';\n\n this.defaultVars.set('octave', 4);\n this.defaultVars.set('volume', 1);\n this.defaultVars.set('private', false);\n \n this.instrument = opts.instrument;\n this.identifier = opts.identifier;\n this.members = opts.members;\n }\n init(scope) {\n super.init(scope);\n this.function_calls = [];\n this.patterns = new Map();\n this.patternCalls = [];\n this.members.forEach(member => {\n // initialize them all now, var inheritence is handled during execution\n member.init(this);\n if(member instanceof _FunctionCall_js__WEBPACK_IMPORTED_MODULE_4__[\"default\"]) {\n this.function_calls.push(member);\n } else if(member instanceof _Pattern_js__WEBPACK_IMPORTED_MODULE_5__[\"PatternStatement\"]) {\n this.patterns.set(member.identifier, member);\n } else if(member instanceof _Pattern_js__WEBPACK_IMPORTED_MODULE_5__[\"PatternCall\"]) {\n this.patternCalls.push(member);\n }\n });\n }\n link(ASTs, parentStyle) {\n for(let patternCall of this.patternCalls) {\n patternCall.link(ASTs, parentStyle, this);\n this.patterns.set(patternCall.prettyprintname, patternCall);\n }\n \n for(let [, pattern] of this.patterns) {\n pattern.link(ASTs, parentStyle, this);\n }\n }\n execute(songIterator) {\n this.inherit();\n console.log(`executing TrackStatement \"${this.name}\"`);\n \n this.function_calls.forEach(function_call => {\n function_call.execute(songIterator);\n });\n \n // weighted random picking\n // https://stackoverflow.com/a/4463613/1784306\n // I don't really understand the above explanation, this is probs wrong\n let totalWeight = 0;\n let weightedOptions = [];\n for(let [patternname, pattern] of this.patterns) {\n console.log(`- pattern \"${patternname}\":`);\n // true = I'm the instrument so if you're private return Nil\n let result = pattern.execute(songIterator, true);\n console.log(' - Result:', result);\n // @TODO: handle multi-measure patterns (via locks?)\n if(result !== _type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"Nil\"]) {\n for(let note of result) {\n if (note.pitch === _MIDI_Note_js__WEBPACK_IMPORTED_MODULE_2__[\"AwaitingDrum\"]) {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_1__[\"DrumBeatInMelodicBeatGroupError\"](pattern);\n }\n }\n \n let chance = pattern.getChance();\n weightedOptions.push({\n noteSet: result,\n lower: totalWeight,\n upper: totalWeight + chance\n });\n totalWeight += chance;\n }\n }\n // binary search would make sense here if I expected more items\n let goal = Math.random() * totalWeight;\n for(let option of weightedOptions) {\n if(option.lower <= goal && goal <= option.upper) {\n console.log(' - Final result:', option.noteSet);\n return option.noteSet;\n }\n }\n console.log(' - Final result:', _type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"Nil\"]);\n return _type_utils_js__WEBPACK_IMPORTED_MODULE_0__[\"Nil\"];\n }\n}\nclass TrackCall {\n constructor(opts) {\n this.import = opts.import;\n this.track = opts.track;\n this.trackStatement = null; // will be set by the loader.\n }\n execute(songIterator) {\n this.trackStatement.execute(songIterator);\n }\n}\n\n\n//# sourceURL=webpack:///./src/ast/Track.js?"); - -/***/ }), - -/***/ "./src/ast/ast_nodes.js": -/*!******************************!*\ - !*** ./src/ast/ast_nodes.js ***! - \******************************/ -/*! exports provided: GlobalScope, MetaStatement, OptionsStatement, ImportStatement, TrackStatement, TrackCall, PatternStatement, PatternExpressionGroup, PatternCall, JoinedPatternExpression, FunctionCall, AnchorArgument, BooleanNot, BooleanAnd, BooleanOr, BeatGroupLiteral, Measure, DrumBeatGroupLiteral, MelodicBeatLiteral, DrumBeatLiteral */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _GlobalScope_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./GlobalScope.js */ \"./src/ast/GlobalScope.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"GlobalScope\", function() { return _GlobalScope_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]; });\n\n/* harmony import */ var _ConfigStatements_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ConfigStatements.js */ \"./src/ast/ConfigStatements.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"MetaStatement\", function() { return _ConfigStatements_js__WEBPACK_IMPORTED_MODULE_1__[\"MetaStatement\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"OptionsStatement\", function() { return _ConfigStatements_js__WEBPACK_IMPORTED_MODULE_1__[\"OptionsStatement\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"ImportStatement\", function() { return _ConfigStatements_js__WEBPACK_IMPORTED_MODULE_1__[\"ImportStatement\"]; });\n\n/* harmony import */ var _Track_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Track.js */ \"./src/ast/Track.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"TrackStatement\", function() { return _Track_js__WEBPACK_IMPORTED_MODULE_2__[\"TrackStatement\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"TrackCall\", function() { return _Track_js__WEBPACK_IMPORTED_MODULE_2__[\"TrackCall\"]; });\n\n/* harmony import */ var _Pattern_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Pattern.js */ \"./src/ast/Pattern.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"PatternStatement\", function() { return _Pattern_js__WEBPACK_IMPORTED_MODULE_3__[\"PatternStatement\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"PatternExpressionGroup\", function() { return _Pattern_js__WEBPACK_IMPORTED_MODULE_3__[\"PatternExpressionGroup\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"PatternCall\", function() { return _Pattern_js__WEBPACK_IMPORTED_MODULE_3__[\"PatternCall\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"JoinedPatternExpression\", function() { return _Pattern_js__WEBPACK_IMPORTED_MODULE_3__[\"JoinedPatternExpression\"]; });\n\n/* harmony import */ var _FunctionCall_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./FunctionCall.js */ \"./src/ast/FunctionCall.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"FunctionCall\", function() { return _FunctionCall_js__WEBPACK_IMPORTED_MODULE_4__[\"default\"]; });\n\n/* harmony import */ var _ArgumentOperators_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./ArgumentOperators.js */ \"./src/ast/ArgumentOperators.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"AnchorArgument\", function() { return _ArgumentOperators_js__WEBPACK_IMPORTED_MODULE_5__[\"AnchorArgument\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"BooleanNot\", function() { return _ArgumentOperators_js__WEBPACK_IMPORTED_MODULE_5__[\"BooleanNot\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"BooleanAnd\", function() { return _ArgumentOperators_js__WEBPACK_IMPORTED_MODULE_5__[\"BooleanAnd\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"BooleanOr\", function() { return _ArgumentOperators_js__WEBPACK_IMPORTED_MODULE_5__[\"BooleanOr\"]; });\n\n/* harmony import */ var _BeatGroups_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./BeatGroups.js */ \"./src/ast/BeatGroups.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"BeatGroupLiteral\", function() { return _BeatGroups_js__WEBPACK_IMPORTED_MODULE_6__[\"BeatGroupLiteral\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"Measure\", function() { return _BeatGroups_js__WEBPACK_IMPORTED_MODULE_6__[\"Measure\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"DrumBeatGroupLiteral\", function() { return _BeatGroups_js__WEBPACK_IMPORTED_MODULE_6__[\"DrumBeatGroupLiteral\"]; });\n\n/* harmony import */ var _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./BeatLiterals.js */ \"./src/ast/BeatLiterals.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"MelodicBeatLiteral\", function() { return _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_7__[\"MelodicBeatLiteral\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"DrumBeatLiteral\", function() { return _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_7__[\"DrumBeatLiteral\"]; });\n\n/**\n * Constructors for most kinds of nodes in the AST (excuding strings and things\n * that can be represented more easily by their JS value).\n *\n * It's probably bad form/risky to parse directly to the form that's\n * interpreted. Eh.\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n//# sourceURL=webpack:///./src/ast/ast_nodes.js?"); - -/***/ }), - -/***/ "./src/ast/errors.js": -/*!***************************!*\ - !*** ./src/ast/errors.js ***! - \***************************/ -/*! exports provided: ImportError, NoSuchStyleError, NoSuchTrackError, NoSuchPatternError, FunctionNameError, FunctionScopeError, FunctionArgumentsError, TooManyBeatsError, MelodicBeatInDrumBeatGroupError, DrumBeatInMelodicBeatGroupError */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ImportError\", function() { return ImportError; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NoSuchStyleError\", function() { return NoSuchStyleError; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NoSuchTrackError\", function() { return NoSuchTrackError; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NoSuchPatternError\", function() { return NoSuchPatternError; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"FunctionNameError\", function() { return FunctionNameError; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"FunctionScopeError\", function() { return FunctionScopeError; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"FunctionArgumentsError\", function() { return FunctionArgumentsError; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"TooManyBeatsError\", function() { return TooManyBeatsError; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MelodicBeatInDrumBeatGroupError\", function() { return MelodicBeatInDrumBeatGroupError; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"DrumBeatInMelodicBeatGroupError\", function() { return DrumBeatInMelodicBeatGroupError; });\n// does this have to be an Error? idc\nclass PlaybackError extends Error {\n constructor(message, scope) {\n super(`${message}\\nScope: \"${scope.name}\"`)\n }\n}\n\n/* Import-related errors */\nclass ImportError extends PlaybackError {\n constructor() {\n super(...arguments);\n }\n}\nclass NoSuchStyleError extends ImportError {\n constructor(identifier, scope) {\n super(`No style with the name \"${identifier}\" was imported`, scope);\n }\n}\nclass NoSuchTrackError extends ImportError {\n constructor(style, track, scope) {\n super(\n `No track with the name \"${track}\" exists in the style \"${style}\"`,\n scope);\n }\n}\nclass NoSuchPatternError extends ImportError {\n constructor(style, track, pattern, scope) {\n super(\n `Pattern \"${style}.${track}.${pattern}\" does not exist`,\n scope);\n }\n}\n\n/* Function-related errors */\nclass FunctionNameError extends PlaybackError {\n constructor(identifier, scope) {\n super(`No function exists with name \"${identifier}\"`, scope);\n }\n}\nclass FunctionScopeError extends PlaybackError {\n constructor(message, scope) {\n super(message, scope);\n }\n}\nclass FunctionArgumentsError extends PlaybackError {\n constructor(message, scope) {\n super(message, scope);\n }\n}\n\n/* Pattern-related errors */\nclass TooManyBeatsError extends PlaybackError {\n constructor(scope) {\n super(\n 'Pattern may only contain 1 BeatGroup. Try the join operator \"&\"',\n scope);\n }\n}\n\n/* Beat-related errors*/\nclass MelodicBeatInDrumBeatGroupError extends PlaybackError {\n constructor(scope) {\n super('Unexpected Melodic Beat in a Drum Beat Group', scope);\n }\n}\nclass DrumBeatInMelodicBeatGroupError extends PlaybackError {\n constructor(scope) {\n super('Unexpected Drum Beat in a Melodic Beat Group', scope);\n }\n}\n\n\n//# sourceURL=webpack:///./src/ast/errors.js?"); - -/***/ }), - -/***/ "./src/ast/function_data.js": -/*!**********************************!*\ - !*** ./src/ast/function_data.js ***! - \**********************************/ -/*! exports provided: assertArgTypes, assertScope, definitions */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"assertArgTypes\", function() { return assertArgTypes; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"assertScope\", function() { return assertScope; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"definitions\", function() { return definitions; });\n/* harmony import */ var _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../lib/tonal.min.js */ \"./src/lib/tonal.min.js\");\n/* harmony import */ var _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./BeatLiterals.js */ \"./src/ast/BeatLiterals.js\");\n/* harmony import */ var _errors_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./errors.js */ \"./src/ast/errors.js\");\n/* harmony import */ var _FunctionCall_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./FunctionCall.js */ \"./src/ast/FunctionCall.js\");\n/* harmony import */ var _type_utils_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./type_utils.js */ \"./src/ast/type_utils.js\");\n\n \n\n\n\n\nlet definitions = new Map();\n\n/**\n * Make an assertion about argument count and types.\n * @param {string} identifier The function name.\n * @param {Array} args The arguments passed to the function.\n * @param {Array.} types Array of the types (typeof) or classes\n * (instanceof) to expect.\n * @param {Scope} scope The scope, for error logging.\n */\nfunction assertArgTypes(identifier, args, types, scope) {\n if(types == '*') return;\n if(args.length != types.length) {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionArgumentsError\"](`\"${identifier}\" requires ${types.length} arguments.`, scope);\n }\n for(let i in args) {\n if(types[i] == '*') continue;\n let arg = args[i];\n if(arg instanceof _FunctionCall_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"]) {\n arg = arg.returns;\n if(arg == '*') {\n continue; // what's the correct functionality here? cry?\n } else if(typeof types[i] == 'string') {\n if(arg != types[i]) {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionArgumentsError\"](`Argument ${Number(i)+1} of \"${identifier}\" must be a ${types[i]}.`, scope);\n }\n } else {\n if(arg != types[i]) {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionArgumentsError\"](`Argument ${Number(i)+1} of \"${identifier}\" must be a ${types[i].name}.`, scope);\n }\n }\n } else {\n if(typeof types[i] == 'string') {\n if(typeof arg != types[i]) {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionArgumentsError\"](`Argument ${Number(i)+1} of \"${identifier}\" must be a ${types[i]}.`, scope);\n }\n } else {\n if(!(arg instanceof types[i])) {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionArgumentsError\"](`Argument ${Number(i)+1} of \"${identifier}\" must be a ${types[i].name}.`, scope);\n }\n }\n }\n }\n}\n/**\n * Make an assertion about the scope in which the function is called.\n * @param {string} identifier The function's name.\n * @param {string='no-meta'} goalscope One of 4 string options:\n * - 'meta': the function throws if it's called outside a @meta block.\n * - 'options': the function throws if it's called outside an @options block.\n * - 'no-config': the function throws if it's called inside a @meta or @options\n * block, but runs anywhere else that the parser will let you call a function.\n * - 'pattern': the function throws if called outside a pattern scope.\n * - 'no-meta' (default): the function throws if it's called inside a @meta\n * block, but runs anywhere else that the parser will let you call a function.\n * @param {Scope} scope The calling scope.\n */\nfunction assertScope(identifier, goalscope = 'no-meta', scope) {\n if(goalscope == 'meta') {\n if(scope.type != '@meta') {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionScopeError\"](`Function \"${identifier}\" must only be called within a @meta block.\"`, scope);\n }\n } else if(goalscope == 'options') {\n if(scope.type != '@options') {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionScopeError\"](`Function \"${identifier}\" must only be called within an @options block.\"`, scope);\n }\n } else if(goalscope == 'no-config') {\n // ensure that config blocks can be resolved at compile time\n if(scope.type == '@meta' || scope.type == '@options') {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionScopeError\"](`Function \"${identifier}\" must not be called within a @meta or @options block.\"`, scope);\n }\n } else if(goalscope == 'pattern') { \n if(scope.type != 'PatternExpressionGroup') {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionScopeError\"](`Function \"${identifier}\" must only be called within a @pattern block.\"`, scope);\n }\n // @TODO: what about @pattern foo private() -- makes no sense but yea\n } else if(goalscope == 'no-meta') { \n if(scope.type == '@meta') {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionScopeError\"](`Function \"${identifier}\" must not be called within a @meta block.\"`, scope);\n }\n }\n}\n/**\n * Define a function.\n * @param {string} identifier The name of the function.\n * @param {Object} opts Options passed. See below.\n * @param {Array.|string='*'} opts.types If set, throw error\n * unless the arguments passed to the function map to these. Can be strings\n * (typeof) or classes (instanceof), or the single string '*' to accept\n * anything. See assertArgTypes above.\n * @param {string='no-meta'} opts.scope Throw error unless the calling\n * scope matches. See assertScope above.\n * @param {string|Function|Nil='*'} opts.returns The return type. If set to '*'\n * it may return anything (for example, choose() returns one of whatever's\n * passed to it regardless of type).\n * @param {Function} func The function to run. It's passed 3 arguments:\n * - args: an array of the arguments passed in the Playback function call.\n * - scope: the calling scope. So it can set in scope.vars.\n * - argErr: a function. If the function does further testing on its\n * arguments and there's an issue, pass this the error message and it throws.\n */\nlet define = function(identifier, opts, func) {\n let definition = {\n types: opts.types || '*',\n returns: opts.returns || '*',\n scope: opts.scope || 'no-meta',\n execute: (args, songIterator, scope) => {\n let argErr = message => {\n throw new _errors_js__WEBPACK_IMPORTED_MODULE_2__[\"FunctionArgumentsError\"](message, scope);\n };\n return func(args, songIterator, scope, argErr);\n }\n };\n \n definitions.set(identifier, definition);\n}\n\n/**\n * Quickly define a single-argument function that simply sets a var of the same\n * name in its parent scope.\n * @param {string} identifier The name of the function.\n * @param {string|Function} type Throw unless the argument is of this type (see\n * assertArgTypes above).\n * @param {?string=null} goalscope Throw error unless the calling scope matches.\n * See assertScope above.\n */\nlet defineVar = function(identifier, type, goalscope = null) {\n let opts = {\n types: [type],\n scope: goalscope,\n returns: _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"]\n };\n define(identifier, opts, (args, songIterator, scope, argErr) => {\n scope.vars.set(identifier, args[0]);\n return _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"];\n })\n}\n\n/**\n * Quickly define a function that sets a a var of the same name in its parent\n * scope. If it has 0 args it sets the var to true, if it has 1 boolean arg\n * it sets the var to that.\n * @param {string} identifier The name of the function.\n * @param {?string=null} goalscope Throw error unless the calling scope matches.\n * See assertScope above.\n */\nlet defineBoolean = function(identifier, goalscope = null) {\n let opts = {\n types: '*',\n scopes: goalscope,\n returns: _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"]\n }\n define(identifier, opts, (args, songIterator, scope, argErr) => {\n if(args.length) {\n assertArgTypes(identifier, args, ['boolean'], scope);\n scope.vars.set(identifier, args[0]);\n } else {\n scope.vars.set(identifier, true);\n }\n return _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"];\n })\n}\n\n/*********** ACTUAL FUNCTION DEFINITIONS ***********/\n\n/*** @meta functions ***/\ndefineVar('name', 'string', 'meta');\ndefineVar('author', 'string', 'meta');\ndefineVar('description', 'string', 'meta');\ndefineVar('playback-version', 'number', 'meta');\n\n/*** @options functions ***/\ndefine('time-signature',\n {\n types: ['number', 'number'],\n scope: 'options',\n returns: _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"]\n },\n (args, songIterator, scope, argErr) => {\n if(!Number.isInteger(Math.log2(args[1]))) {\n argErr('Argument 2 of \"time-signature\" must be a power of 2.');\n }\n scope.vars.set('time-signature', [args[0], args[1]]);\n return _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"];\n });\ndefineBoolean('swing', 'options');\n\n/*** anywhere but @meta functions ***/\ndefine('volume',\n {\n types: ['number'],\n scope: 'no-meta',\n returns: _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"]\n },\n (args, songIterator, scope, argErr) => {\n if(args[0] < 0 || args[0] > 1) {\n argErr('Argument 1 of \"volume\" must be in range 0-1 (inclusive).');\n }\n scope.vars.set('volume', args[0]);\n return _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"];\n });\ndefineBoolean('invertible', 'no-meta');\ndefine('octave',\n {\n types: ['number'],\n scope: 'no-meta',\n returns: _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"]\n },\n (args, songIterator, scope, argErr) => {\n if(!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) {\n argErr('Argument 1 of \"octave\" must be an integer 0-9.');\n }\n scope.vars.set('octave', args[0]);\n return _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"];\n });\n\n/*** anywhere but config functions (strictly dynamic functions) ***/\ndefine('choose',\n {\n types: '*',\n scope: 'no-config',\n returns: '*'\n },\n (args, songIterator, scope, argErr) => {\n let nonNilArgs = args.filter(arg => arg !== _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"]);\n if(nonNilArgs.length) {\n let index = Math.floor(Math.random() * nonNilArgs.length);\n return nonNilArgs[index];\n } else {\n return _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"];\n }\n });\n\nlet anchorOrNumberToChordAndRoot = function(arg, songIterator) {\n let anchorChord, root;\n if(typeof arg == 'number') {\n anchorChord = _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"].getAnchorChord(\n null, songIterator, 1);\n root = _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"].anchorChordToRoot(anchorChord, arg, 4);\n } else if(arg.anchor) {\n anchorChord = _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"].getAnchorChord(\n arg.anchor, songIterator, 1);\n root = _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"].anchorChordToRoot(anchorChord, 1, 4);\n }\n return [anchorChord, root];\n};\n\ndefine('progression',\n {\n types: '*',\n scope: 'no-config',\n returns: 'boolean'\n },\n (args, songIterator, scope, argErr) => {\n for(let i in args) {\n let arg = args[i];\n let [,goal] = anchorOrNumberToChordAndRoot(arg, songIterator);\n if(!goal) {\n argErr('Arguments of \"progression\" must be numbers or anchors.');\n }\n let actualMeasure = songIterator.getRelative(Number(i));\n if(!actualMeasure) return false;\n let actualChord = _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"].normalizeChord(actualMeasure[0]);\n let actual = _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"].anchorChordToRoot(\n actualChord, 1, 4);\n if(actual != goal) return false;\n }\n return true;\n });\ndefine('in-scale',\n {\n types: '*',\n scope: 'no-config',\n returns: 'boolean'\n },\n (args, songIterator, scope, argErr) => {\n let [,note] = anchorOrNumberToChordAndRoot(args[0], songIterator);\n let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator);\n if(!note || !goalChord) {\n argErr('Arguments of \"in-scale\" must be numbers or anchors.');\n }\n let goalScaleName = _BeatLiterals_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"].chordToScaleName(goalChord);\n let goalScale = _lib_tonal_min_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Scale.notes(goalTonic, goalScaleName);\n return goalScale.includes(note);\n });\ndefine('beat-defined',\n {\n types: ['number'],\n scope: 'no-config',\n returns: 'boolean'\n },\n (args, songIterator, scope, argErr) => {\n let measure = songIterator.getRelative(0);\n return measure[args[0]] !== null;\n });\n\n/*** pattern-only functions ***/\ndefineBoolean('private', 'pattern');\ndefineVar('length', 'number', 'pattern');\ndefine('chance',\n {\n types: ['number'],\n scope: 'pattern',\n returns: _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"]\n },\n (args, songIterator, scope, argErr) => {\n if(args[0] < 0 || args[0] > 1) {\n argErr('Argument 1 of \"chance\" must be in range 0-1 (inclusive).');\n }\n scope.vars.set('chance', args[0]);\n return _type_utils_js__WEBPACK_IMPORTED_MODULE_4__[\"Nil\"];\n });\n\n\n\n\n//# sourceURL=webpack:///./src/ast/function_data.js?"); - -/***/ }), - -/***/ "./src/ast/type_utils.js": -/*!*******************************!*\ - !*** ./src/ast/type_utils.js ***! - \*******************************/ -/*! exports provided: Nil, cast_bool */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Nil\", function() { return Nil; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"cast_bool\", function() { return cast_bool; });\nlet Nil = Symbol('Nil');\nlet cast_bool = function(arg) {\n if(arg === Nil || arg === false) {\n return false;\n } else {\n return true;\n }\n}\n\n\n\n\n//# sourceURL=webpack:///./src/ast/type_utils.js?"); - -/***/ }), - -/***/ "./src/index.js": -/*!**********************!*\ - !*** ./src/index.js ***! - \**********************/ -/*! exports provided: PlaybackStyle, Player */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _PlaybackStyle_PlaybackStyle_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./PlaybackStyle/PlaybackStyle.js */ \"./src/PlaybackStyle/PlaybackStyle.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"PlaybackStyle\", function() { return _PlaybackStyle_PlaybackStyle_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]; });\n\n/* harmony import */ var _Player_Player_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Player/Player.js */ \"./src/Player/Player.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"Player\", function() { return _Player_Player_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"]; });\n\n//import {load} from './loader/loader.js';\n//import {parse} from './parser/parser.js';\n\n\n\n\n\n\n//# sourceURL=webpack:///./src/index.js?"); - -/***/ }), - -/***/ "./src/lexer/lexer.js": -/*!****************************!*\ - !*** ./src/lexer/lexer.js ***! - \****************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _lib_moo_moo_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../lib/moo/moo.js */ \"./src/lib/moo/moo.js\");\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (_lib_moo_moo_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].states({\n main: {\n comment: {\n match:/\\/\\/.*?(?:\\n|$)/, // consuming newline should be fine since this is _?. Can I do eof anchor here? Guess we'll find out \n lineBreaks: true\n },\n quoted_string: /\"(?:[^\\\\\"\\n]|\\\\.)*\"/, // thanx https://stackoverflow.com/a/249937/1784306\n ws: {\n match: /\\s+/,\n lineBreaks: true\n },\n at_rule: ['@meta', '@options', '@import', '@track', '@pattern'],\n identifier: {\n // start with alpha, may contain digits and dashes but not end with dash\n match: /[a-zA-z](?:[a-zA-Z\\-\\d]*[a-zA-Z\\d])?/,\n keywords: {\n keyword: ['if', 'as'],\n boolean: ['true', 'false']\n }\n },\n number: /(?:\\d*\\.)?\\d+/,\n brackets: ['{', '}', '(', ')'],\n left_angle: {match: '<', push: 'beat'},\n operators: ['&', '+', '-', '*', '/', '.']\n },\n beat: {\n beat_ws: / +/,\n beat_colon: ':',\n beat_number: /(?:\\d*\\.)?\\d+/,\n beat_flag: /[a-zA-Z]/,\n beat_right_angle: {match: '>', pop: true},\n beat_operators: ['|', '+', '-', '*', '/']\n }\n}));\n\n\n//# sourceURL=webpack:///./src/lexer/lexer.js?"); - -/***/ }), - -/***/ "./src/lib/moo/moo.js": -/*!****************************!*\ - !*** ./src/lib/moo/moo.js ***! - \****************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = ((function() {\n 'use strict';\n\n var hasOwnProperty = Object.prototype.hasOwnProperty\n\n // polyfill assign(), so we support IE9+\n var assign = typeof Object.assign === 'function' ? Object.assign :\n // https://tc39.github.io/ecma262/#sec-object.assign\n function(target, sources) {\n if (target == null) {\n throw new TypeError('Target cannot be null or undefined');\n }\n target = Object(target)\n\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i]\n if (source == null) continue\n\n for (var key in source) {\n if (hasOwnProperty.call(source, key)) {\n target[key] = source[key]\n }\n }\n }\n return target\n }\n\n var hasSticky = typeof new RegExp().sticky === 'boolean'\n\n /***************************************************************************/\n\n function isRegExp(o) { return o && o.constructor === RegExp }\n function isObject(o) { return o && typeof o === 'object' && o.constructor !== RegExp && !Array.isArray(o) }\n\n function reEscape(s) {\n return s.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&')\n }\n function reGroups(s) {\n var re = new RegExp('|' + s)\n return re.exec('').length - 1\n }\n function reCapture(s) {\n return '(' + s + ')'\n }\n function reUnion(regexps) {\n var source = regexps.map(function(s) {\n return \"(?:\" + s + \")\"\n }).join('|')\n return \"(?:\" + source + \")\"\n }\n\n function regexpOrLiteral(obj) {\n if (typeof obj === 'string') {\n return '(?:' + reEscape(obj) + ')'\n\n } else if (isRegExp(obj)) {\n // TODO: consider /u support\n if (obj.ignoreCase) { throw new Error('RegExp /i flag not allowed') }\n if (obj.global) { throw new Error('RegExp /g flag is implied') }\n if (obj.sticky) { throw new Error('RegExp /y flag is implied') }\n if (obj.multiline) { throw new Error('RegExp /m flag is implied') }\n return obj.source\n\n } else {\n throw new Error('not a pattern: ' + obj)\n }\n }\n\n function objectToRules(object) {\n var keys = Object.getOwnPropertyNames(object)\n var result = []\n for (var i=0; i 0) {\n throw new Error(\"RegExp has capture groups: \" + regexp + \"\\nUse (?: … ) instead\")\n }\n if (!hasStates && (options.pop || options.push || options.next)) {\n throw new Error(\"State-switching options are not allowed in stateless lexers (for token '\" + options.tokenType + \"')\")\n }\n\n // try and detect rules matching newlines\n if (!options.lineBreaks && regexp.test('\\n')) {\n throw new Error('Rule should declare lineBreaks: ' + regexp)\n }\n\n // store regex\n parts.push(reCapture(pat))\n }\n\n var suffix = hasSticky ? '' : '|(?:)'\n var flags = hasSticky ? 'ym' : 'gm'\n var combined = new RegExp(reUnion(parts) + suffix, flags)\n\n return {regexp: combined, groups: groups, error: errorRule}\n }\n\n function compile(rules) {\n var result = compileRules(rules)\n return new Lexer({start: result}, 'start')\n }\n\n function compileStates(states, start) {\n var keys = Object.getOwnPropertyNames(states)\n if (!start) start = keys[0]\n\n var map = Object.create(null)\n for (var i=0; i: a function to convert from instrument names to URL\n * - `destination`: by default Soundfont uses the `audioContext.destination` but you can override it.\n * - `gain`: the gain of the player (1 by default)\n * - `notes`: an array of the notes to decode. It can be an array of strings\n * with note names or an array of numbers with midi note numbers. This is a\n * performance option: since decoding mp3 is a cpu intensive process, you can limit\n * limit the number of notes you want and reduce the time to load the instrument.\n *\n * @param {AudioContext} ac - the audio context\n * @param {String} name - the instrument name. For example: 'acoustic_grand_piano'\n * @param {Object} options - (Optional) the same options as Soundfont.loadBuffers\n * @return {Promise}\n *\n * @example\n * var Soundfont = require('sounfont-player')\n * Soundfont.instrument('marimba').then(function (marimba) {\n * marimba.play('C4')\n * })\n */\n function instrument (ac, name, options) {\n if (arguments.length === 1) return function (n, o) { return instrument(ac, n, o) }\n var opts = options || {}\n var isUrl = opts.isSoundfontURL || isSoundfontURL\n var toUrl = opts.nameToUrl || nameToUrl\n var url = isUrl(name) ? name : toUrl(name, opts.soundfont, opts.format)\n \n return load(ac, url, { only: opts.only || opts.notes }).then(function (buffers) {\n var p = player(ac, buffers, opts).connect(opts.destination ? opts.destination : ac.destination)\n p.url = url\n p.name = name\n return p\n })\n }\n \n function isSoundfontURL (name) {\n return /\\.js(\\?.*)?$/i.test(name)\n }\n \n /**\n * Given an instrument name returns a URL to to the Benjamin Gleitzman's\n * package of [pre-rendered sound fonts](https://github.com/gleitz/midi-js-soundfonts)\n *\n * @param {String} name - instrument name\n * @param {String} soundfont - (Optional) the soundfont name. One of 'FluidR3_GM'\n * or 'MusyngKite' ('MusyngKite' by default)\n * @param {String} format - (Optional) Can be 'mp3' or 'ogg' (mp3 by default)\n * @returns {String} the Soundfont file url\n * @example\n * var Soundfont = require('soundfont-player')\n * Soundfont.nameToUrl('marimba', 'mp3')\n */\n function nameToUrl (name, sf, format) {\n format = format === 'ogg' ? format : 'mp3'\n sf = sf === 'FluidR3_GM' ? sf : 'MusyngKite'\n return 'https://gleitz.github.io/midi-js-soundfonts/' + sf + '/' + name + '-' + format + '.js'\n }\n \n // In the 1.0.0 release it will be:\n // var Soundfont = {}\n var Soundfont = require('./legacy')\n Soundfont.instrument = instrument\n Soundfont.nameToUrl = nameToUrl\n \n if (typeof module === 'object' && module.exports) module.exports = Soundfont\n if (typeof window !== 'undefined') window.Soundfont = Soundfont\n \n },{\"./legacy\":2,\"audio-loader\":6,\"sample-player\":10}],2:[function(require,module,exports){\n 'use strict'\n \n var parser = require('note-parser')\n \n /**\n * Create a Soundfont object\n *\n * @param {AudioContext} context - the [audio context](https://developer.mozilla.org/en/docs/Web/API/AudioContext)\n * @param {Function} nameToUrl - (Optional) a function that maps the sound font name to the url\n * @return {Soundfont} a soundfont object\n */\n function Soundfont (ctx, nameToUrl) {\n console.warn('new Soundfont() is deprected')\n console.log('Please use Soundfont.instrument() instead of new Soundfont().instrument()')\n if (!(this instanceof Soundfont)) return new Soundfont(ctx)\n \n this.nameToUrl = nameToUrl || Soundfont.nameToUrl\n this.ctx = ctx\n this.instruments = {}\n this.promises = []\n }\n \n Soundfont.prototype.onready = function (callback) {\n console.warn('deprecated API')\n console.log('Please use Promise.all(Soundfont.instrument(), Soundfont.instrument()).then() instead of new Soundfont().onready()')\n Promise.all(this.promises).then(callback)\n }\n \n Soundfont.prototype.instrument = function (name, options) {\n console.warn('new Soundfont().instrument() is deprecated.')\n console.log('Please use Soundfont.instrument() instead.')\n var ctx = this.ctx\n name = name || 'default'\n if (name in this.instruments) return this.instruments[name]\n var inst = {name: name, play: oscillatorPlayer(ctx, options)}\n this.instruments[name] = inst\n if (name !== 'default') {\n var promise = Soundfont.instrument(ctx, name, options).then(function (instrument) {\n inst.play = instrument.play\n return inst\n })\n this.promises.push(promise)\n inst.onready = function (cb) {\n console.warn('onready is deprecated. Use Soundfont.instrument().then()')\n promise.then(cb)\n }\n } else {\n inst.onready = function (cb) {\n console.warn('onready is deprecated. Use Soundfont.instrument().then()')\n cb()\n }\n }\n return inst\n }\n \n /*\n * Load the buffers of a given instrument name. It returns a promise that resolves\n * to a hash with midi note numbers as keys, and audio buffers as values.\n *\n * @param {AudioContext} ac - the audio context\n * @param {String} name - the instrument name (it accepts an url if starts with \"http\")\n * @param {Object} options - (Optional) options object\n * @return {Promise} a promise that resolves to a Hash of { midiNoteNum: }\n *\n * The options object accepts the following keys:\n *\n * - nameToUrl {Function}: a function to convert from instrument names to urls.\n * By default it uses Benjamin Gleitzman's package of\n * [pre-rendered sound fonts](https://github.com/gleitz/midi-js-soundfonts)\n * - notes {Array}: the list of note names to be decoded (all by default)\n *\n * @example\n * var Soundfont = require('soundfont-player')\n * Soundfont.loadBuffers(ctx, 'acoustic_grand_piano').then(function(buffers) {\n * buffers[60] // => An corresponding to note C4\n * })\n */\n function loadBuffers (ac, name, options) {\n console.warn('Soundfont.loadBuffers is deprecate.')\n console.log('Use Soundfont.instrument(..) and get buffers properties from the result.')\n return Soundfont.instrument(ac, name, options).then(function (inst) {\n return inst.buffers\n })\n }\n Soundfont.loadBuffers = loadBuffers\n \n /**\n * Returns a function that plays an oscillator\n *\n * @param {AudioContext} ac - the audio context\n * @param {Hash} defaultOptions - (Optional) a hash of options:\n * - vcoType: the oscillator type (default: 'sine')\n * - gain: the output gain value (default: 0.4)\n * - destination: the player destination (default: ac.destination)\n */\n function oscillatorPlayer (ctx, defaultOptions) {\n defaultOptions = defaultOptions || {}\n return function (note, time, duration, options) {\n console.warn('The oscillator player is deprecated.')\n console.log('Starting with version 0.9.0 you will have to wait until the soundfont is loaded to play sounds.')\n var midi = note > 0 && note < 129 ? +note : parser.midi(note)\n var freq = midi ? parser.midiToFreq(midi, 440) : null\n if (!freq) return\n \n duration = duration || 0.2\n \n options = options || {}\n var destination = options.destination || defaultOptions.destination || ctx.destination\n var vcoType = options.vcoType || defaultOptions.vcoType || 'sine'\n var gain = options.gain || defaultOptions.gain || 0.4\n \n var vco = ctx.createOscillator()\n vco.type = vcoType\n vco.frequency.value = freq\n \n /* VCA */\n var vca = ctx.createGain()\n vca.gain.value = gain\n \n /* Connections */\n vco.connect(vca)\n vca.connect(destination)\n \n vco.start(time)\n if (duration > 0) vco.stop(time + duration)\n return vco\n }\n }\n \n /**\n * Given a note name, return the note midi number\n *\n * @name noteToMidi\n * @function\n * @param {String} noteName\n * @return {Integer} the note midi number or null if not a valid note name\n */\n Soundfont.noteToMidi = parser.midi\n \n module.exports = Soundfont\n \n },{\"note-parser\":8}],3:[function(require,module,exports){\n module.exports = ADSR\n \n function ADSR(audioContext){\n var node = audioContext.createGain()\n \n var voltage = node._voltage = getVoltage(audioContext)\n var value = scale(voltage)\n var startValue = scale(voltage)\n var endValue = scale(voltage)\n \n node._startAmount = scale(startValue)\n node._endAmount = scale(endValue)\n \n node._multiplier = scale(value)\n node._multiplier.connect(node)\n node._startAmount.connect(node)\n node._endAmount.connect(node)\n \n node.value = value.gain\n node.startValue = startValue.gain\n node.endValue = endValue.gain\n \n node.startValue.value = 0\n node.endValue.value = 0\n \n Object.defineProperties(node, props)\n return node\n }\n \n var props = {\n \n attack: { value: 0, writable: true },\n decay: { value: 0, writable: true },\n sustain: { value: 1, writable: true },\n release: {value: 0, writable: true },\n \n getReleaseDuration: {\n value: function(){\n return this.release\n }\n },\n \n start: {\n value: function(at){\n var target = this._multiplier.gain\n var startAmount = this._startAmount.gain\n var endAmount = this._endAmount.gain\n \n this._voltage.start(at)\n this._decayFrom = this._decayFrom = at+this.attack\n this._startedAt = at\n \n var sustain = this.sustain\n \n target.cancelScheduledValues(at)\n startAmount.cancelScheduledValues(at)\n endAmount.cancelScheduledValues(at)\n \n endAmount.setValueAtTime(0, at)\n \n if (this.attack){\n target.setValueAtTime(0, at)\n target.linearRampToValueAtTime(1, at + this.attack)\n \n startAmount.setValueAtTime(1, at)\n startAmount.linearRampToValueAtTime(0, at + this.attack)\n } else {\n target.setValueAtTime(1, at)\n startAmount.setValueAtTime(0, at)\n }\n \n if (this.decay){\n target.setTargetAtTime(sustain, this._decayFrom, getTimeConstant(this.decay))\n }\n }\n },\n \n stop: {\n value: function(at, isTarget){\n if (isTarget){\n at = at - this.release\n }\n \n var endTime = at + this.release\n if (this.release){\n \n var target = this._multiplier.gain\n var startAmount = this._startAmount.gain\n var endAmount = this._endAmount.gain\n \n target.cancelScheduledValues(at)\n startAmount.cancelScheduledValues(at)\n endAmount.cancelScheduledValues(at)\n \n var expFalloff = getTimeConstant(this.release)\n \n // truncate attack (required as linearRamp is removed by cancelScheduledValues)\n if (this.attack && at < this._decayFrom){\n var valueAtTime = getValue(0, 1, this._startedAt, this._decayFrom, at)\n target.linearRampToValueAtTime(valueAtTime, at)\n startAmount.linearRampToValueAtTime(1-valueAtTime, at)\n startAmount.setTargetAtTime(0, at, expFalloff)\n }\n \n endAmount.setTargetAtTime(1, at, expFalloff)\n target.setTargetAtTime(0, at, expFalloff)\n }\n \n this._voltage.stop(endTime)\n return endTime\n }\n },\n \n onended: {\n get: function(){\n return this._voltage.onended\n },\n set: function(value){\n this._voltage.onended = value\n }\n }\n \n }\n \n var flat = new Float32Array([1,1])\n function getVoltage(context){\n var voltage = context.createBufferSource()\n var buffer = context.createBuffer(1, 2, context.sampleRate)\n buffer.getChannelData(0).set(flat)\n voltage.buffer = buffer\n voltage.loop = true\n return voltage\n }\n \n function scale(node){\n var gain = node.context.createGain()\n node.connect(gain)\n return gain\n }\n \n function getTimeConstant(time){\n return Math.log(time+1)/Math.log(100)\n }\n \n function getValue(start, end, fromTime, toTime, at){\n var difference = end - start\n var time = toTime - fromTime\n var truncateTime = at - fromTime\n var phase = truncateTime / time\n var value = start + phase * difference\n \n if (value <= start) {\n value = start\n }\n if (value >= end) {\n value = end\n }\n \n return value\n }\n \n },{}],4:[function(require,module,exports){\n 'use strict'\n \n // DECODE UTILITIES\n function b64ToUint6 (nChr) {\n return nChr > 64 && nChr < 91 ? nChr - 65\n : nChr > 96 && nChr < 123 ? nChr - 71\n : nChr > 47 && nChr < 58 ? nChr + 4\n : nChr === 43 ? 62\n : nChr === 47 ? 63\n : 0\n }\n \n // Decode Base64 to Uint8Array\n // ---------------------------\n function decode (sBase64, nBlocksSize) {\n var sB64Enc = sBase64.replace(/[^A-Za-z0-9\\+\\/]/g, '')\n var nInLen = sB64Enc.length\n var nOutLen = nBlocksSize\n ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize\n : nInLen * 3 + 1 >> 2\n var taBytes = new Uint8Array(nOutLen)\n \n for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {\n nMod4 = nInIdx & 3\n nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4\n if (nMod4 === 3 || nInLen - nInIdx === 1) {\n for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {\n taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255\n }\n nUint24 = 0\n }\n }\n return taBytes\n }\n \n module.exports = { decode: decode }\n \n },{}],5:[function(require,module,exports){\n /* global XMLHttpRequest */\n 'use strict'\n \n /**\n * Given a url and a return type, returns a promise to the content of the url\n * Basically it wraps a XMLHttpRequest into a Promise\n *\n * @param {String} url\n * @param {String} type - can be 'text' or 'arraybuffer'\n * @return {Promise}\n */\n module.exports = function (url, type) {\n return new Promise(function (done, reject) {\n var req = new XMLHttpRequest()\n if (type) req.responseType = type\n \n req.open('GET', url)\n req.onload = function () {\n req.status === 200 ? done(req.response) : reject(Error(req.statusText))\n }\n req.onerror = function () { reject(Error('Network Error')) }\n req.send()\n })\n }\n \n },{}],6:[function(require,module,exports){\n 'use strict'\n \n var base64 = require('./base64')\n var fetch = require('./fetch')\n \n // Given a regex, return a function that test if against a string\n function fromRegex (r) {\n return function (o) { return typeof o === 'string' && r.test(o) }\n }\n // Try to apply a prefix to a name\n function prefix (pre, name) {\n return typeof pre === 'string' ? pre + name\n : typeof pre === 'function' ? pre(name)\n : name\n }\n \n /**\n * Load one or more audio files\n *\n *\n * Possible option keys:\n *\n * - __from__ {Function|String}: a function or string to convert from file names to urls.\n * If is a string it will be prefixed to the name:\n * `load(ac, 'snare.mp3', { from: 'http://audio.net/samples/' })`\n * If it's a function it receives the file name and should return the url as string.\n * - __only__ {Array} - when loading objects, if provided, only the given keys\n * will be included in the decoded object:\n * `load(ac, 'piano.json', { only: ['C2', 'D2'] })`\n *\n * @param {AudioContext} ac - the audio context\n * @param {Object} source - the object to be loaded\n * @param {Object} options - (Optional) the load options for that object\n * @param {Object} defaultValue - (Optional) the default value to return as\n * in a promise if not valid loader found\n */\n function load (ac, source, options, defVal) {\n var loader =\n // Basic audio loading\n isArrayBuffer(source) ? loadArrayBuffer\n : isAudioFileName(source) ? loadAudioFile\n : isPromise(source) ? loadPromise\n // Compound objects\n : isArray(source) ? loadArrayData\n : isObject(source) ? loadObjectData\n : isJsonFileName(source) ? loadJsonFile\n // Base64 encoded audio\n : isBase64Audio(source) ? loadBase64Audio\n : isJsFileName(source) ? loadMidiJSFile\n : null\n \n var opts = options || {}\n return loader ? loader(ac, source, opts)\n : defVal ? Promise.resolve(defVal)\n : Promise.reject('Source not valid (' + source + ')')\n }\n load.fetch = fetch\n \n // BASIC AUDIO LOADING\n // ===================\n \n // Load (decode) an array buffer\n function isArrayBuffer (o) { return o instanceof ArrayBuffer }\n function loadArrayBuffer (ac, array, options) {\n return new Promise(function (done, reject) {\n ac.decodeAudioData(array,\n function (buffer) { done(buffer) },\n function () { reject(\"Can't decode audio data (\" + array.slice(0, 30) + '...)') }\n )\n })\n }\n \n // Load an audio filename\n var isAudioFileName = fromRegex(/\\.(mp3|wav|ogg)(\\?.*)?$/i)\n function loadAudioFile (ac, name, options) {\n var url = prefix(options.from, name)\n return load(ac, load.fetch(url, 'arraybuffer'), options)\n }\n \n // Load the result of a promise\n function isPromise (o) { return o && typeof o.then === 'function' }\n function loadPromise (ac, promise, options) {\n return promise.then(function (value) {\n return load(ac, value, options)\n })\n }\n \n // COMPOUND OBJECTS\n // ================\n \n // Try to load all the items of an array\n var isArray = Array.isArray\n function loadArrayData (ac, array, options) {\n return Promise.all(array.map(function (data) {\n return load(ac, data, options, data)\n }))\n }\n \n // Try to load all the values of a key/value object\n function isObject (o) { return o && typeof o === 'object' }\n function loadObjectData (ac, obj, options) {\n var dest = {}\n var promises = Object.keys(obj).map(function (key) {\n if (options.only && options.only.indexOf(key) === -1) return null\n var value = obj[key]\n return load(ac, value, options, value).then(function (audio) {\n dest[key] = audio\n })\n })\n return Promise.all(promises).then(function () { return dest })\n }\n \n // Load the content of a JSON file\n var isJsonFileName = fromRegex(/\\.json(\\?.*)?$/i)\n function loadJsonFile (ac, name, options) {\n var url = prefix(options.from, name)\n return load(ac, load.fetch(url, 'text').then(JSON.parse), options)\n }\n \n // BASE64 ENCODED FORMATS\n // ======================\n \n // Load strings with Base64 encoded audio\n var isBase64Audio = fromRegex(/^data:audio/)\n function loadBase64Audio (ac, source, options) {\n var i = source.indexOf(',')\n return load(ac, base64.decode(source.slice(i + 1)).buffer, options)\n }\n \n // Load .js files with MidiJS soundfont prerendered audio\n var isJsFileName = fromRegex(/\\.js(\\?.*)?$/i)\n function loadMidiJSFile (ac, name, options) {\n var url = prefix(options.from, name)\n return load(ac, load.fetch(url, 'text').then(midiJsToJson), options)\n }\n \n // convert a MIDI.js javascript soundfont file to json\n function midiJsToJson (data) {\n var begin = data.indexOf('MIDI.Soundfont.')\n if (begin < 0) throw Error('Invalid MIDI.js Soundfont format')\n begin = data.indexOf('=', begin) + 2\n var end = data.lastIndexOf(',')\n return JSON.parse(data.slice(begin, end) + '}')\n }\n \n if (typeof module === 'object' && module.exports) module.exports = load\n if (typeof window !== 'undefined') window.loadAudio = load\n \n },{\"./base64\":4,\"./fetch\":5}],7:[function(require,module,exports){\n (function (global){\n (function(e){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=e()}else if(typeof define===\"function\"&&__webpack_require__(/*! !webpack amd options */ \"./node_modules/webpack/buildin/amd-options.js\")){define([],e)}else{var t;if(typeof window!==\"undefined\"){t=window}else if(typeof global!==\"undefined\"){t=global}else if(typeof self!==\"undefined\"){t=self}else{t=this}t.midimessage=e()}})(function(){var e,t,s;return function o(e,t,s){function a(n,i){if(!t[n]){if(!e[n]){var l=typeof require==\"function\"&&require;if(!i&&l)return l(n,!0);if(r)return r(n,!0);var h=new Error(\"Cannot find module '\"+n+\"'\");throw h.code=\"MODULE_NOT_FOUND\",h}var c=t[n]={exports:{}};e[n][0].call(c.exports,function(t){var s=e[n][1][t];return a(s?s:t)},c,c.exports,o,e,t,s)}return t[n].exports}var r=typeof require==\"function\"&&require;for(var n=0;n6?null:C.charAt(t)+f(n)+a(r)}function p(t){if((r(t)||e(t))&&t>=0&&t<128)return+t;var n=i(t);return n&&u(n.midi)?n.midi:null}function s(t,n){var r=p(t);return null===r?null:c(r,n)}function d(t){return(i(t)||{}).letter}function m(t){return(i(t)||{}).acc}function h(t){return(i(t)||{}).pc}function v(t){return(i(t)||{}).step}function g(t){return(i(t)||{}).alt}function x(t){return(i(t)||{}).chroma}function y(t){return(i(t)||{}).oct}var b=/^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\\d*)\\s*(.*)\\s*$/,A=[0,2,4,5,7,9,11],C=\"CDEFGAB\";t.regex=o,t.parse=i,t.build=l,t.midi=p,t.freq=s,t.letter=d,t.acc=m,t.pc=h,t.step=v,t.alt=g,t.chroma=x,t.oct=y});\n \n \n },{}],9:[function(require,module,exports){\n \n module.exports = function (player) {\n /**\n * Adds a listener of an event\n * @chainable\n * @param {String} event - the event name\n * @param {Function} callback - the event handler\n * @return {SamplePlayer} the player\n * @example\n * player.on('start', function(time, note) {\n * console.log(time, note)\n * })\n */\n player.on = function (event, cb) {\n if (arguments.length === 1 && typeof event === 'function') return player.on('event', event)\n var prop = 'on' + event\n var old = player[prop]\n player[prop] = old ? chain(old, cb) : cb\n return player\n }\n return player\n }\n \n function chain (fn1, fn2) {\n return function (a, b, c, d) { fn1(a, b, c, d); fn2(a, b, c, d) }\n }\n \n },{}],10:[function(require,module,exports){\n 'use strict'\n \n var player = require('./player')\n var events = require('./events')\n var notes = require('./notes')\n var scheduler = require('./scheduler')\n var midi = require('./midi')\n \n function SamplePlayer (ac, source, options) {\n return midi(scheduler(notes(events(player(ac, source, options)))))\n }\n \n if (typeof module === 'object' && module.exports) module.exports = SamplePlayer\n if (typeof window !== 'undefined') window.SamplePlayer = SamplePlayer\n \n },{\"./events\":9,\"./midi\":11,\"./notes\":12,\"./player\":13,\"./scheduler\":14}],11:[function(require,module,exports){\n var midimessage = require('midimessage')\n \n module.exports = function (player) {\n /**\n * Connect a player to a midi input\n *\n * The options accepts:\n *\n * - channel: the channel to listen to. Listen to all channels by default.\n *\n * @param {MIDIInput} input\n * @param {Object} options - (Optional)\n * @return {SamplePlayer} the player\n * @example\n * var piano = player(...)\n * window.navigator.requestMIDIAccess().then(function (midiAccess) {\n * midiAccess.inputs.forEach(function (midiInput) {\n * piano.listenToMidi(midiInput)\n * })\n * })\n */\n player.listenToMidi = function (input, options) {\n var started = {}\n var opts = options || {}\n var gain = opts.gain || function (vel) { return vel / 127 }\n \n input.onmidimessage = function (msg) {\n var mm = msg.messageType ? msg : midimessage(msg)\n if (mm.messageType === 'noteon' && mm.velocity === 0) {\n mm.messageType = 'noteoff'\n }\n if (opts.channel && mm.channel !== opts.channel) return\n \n switch (mm.messageType) {\n case 'noteon':\n started[mm.key] = player.play(mm.key, 0, { gain: gain(mm.velocity) })\n break\n case 'noteoff':\n if (started[mm.key]) {\n started[mm.key].stop()\n delete started[mm.key]\n }\n break\n }\n }\n return player\n }\n return player\n }\n \n },{\"midimessage\":7}],12:[function(require,module,exports){\n 'use strict'\n \n var note = require('note-parser')\n var isMidi = function (n) { return n !== null && n !== [] && n >= 0 && n < 129 }\n var toMidi = function (n) { return isMidi(n) ? +n : note.midi(n) }\n \n // Adds note name to midi conversion\n module.exports = function (player) {\n if (player.buffers) {\n var map = player.opts.map\n var toKey = typeof map === 'function' ? map : toMidi\n var mapper = function (name) {\n return name ? toKey(name) || name : null\n }\n \n player.buffers = mapBuffers(player.buffers, mapper)\n var start = player.start\n player.start = function (name, when, options) {\n var key = mapper(name)\n var dec = key % 1\n if (dec) {\n key = Math.floor(key)\n options = Object.assign(options || {}, { cents: Math.floor(dec * 100) })\n }\n return start(key, when, options)\n }\n }\n return player\n }\n \n function mapBuffers (buffers, toKey) {\n return Object.keys(buffers).reduce(function (mapped, name) {\n mapped[toKey(name)] = buffers[name]\n return mapped\n }, {})\n }\n \n },{\"note-parser\":15}],13:[function(require,module,exports){\n /* global AudioBuffer */\n 'use strict'\n \n var ADSR = require('adsr')\n \n var EMPTY = {}\n var DEFAULTS = {\n gain: 1,\n attack: 0.01,\n decay: 0.1,\n sustain: 0.9,\n release: 0.3,\n loop: false,\n cents: 0,\n loopStart: 0,\n loopEnd: 0\n }\n \n /**\n * Create a sample player.\n *\n * @param {AudioContext} ac - the audio context\n * @param {ArrayBuffer|Object} source\n * @param {Onject} options - (Optional) an options object\n * @return {player} the player\n * @example\n * var SamplePlayer = require('sample-player')\n * var ac = new AudioContext()\n * var snare = SamplePlayer(ac, )\n * snare.play()\n */\n function SamplePlayer (ac, source, options) {\n var connected = false\n var nextId = 0\n var tracked = {}\n var out = ac.createGain()\n out.gain.value = 1\n \n var opts = Object.assign({}, DEFAULTS, options)\n \n /**\n * @namespace\n */\n var player = { context: ac, out: out, opts: opts }\n if (source instanceof AudioBuffer) player.buffer = source\n else player.buffers = source\n \n /**\n * Start a sample buffer.\n *\n * The returned object has a function `stop(when)` to stop the sound.\n *\n * @param {String} name - the name of the buffer. If the source of the\n * SamplePlayer is one sample buffer, this parameter is not required\n * @param {Float} when - (Optional) when to start (current time if by default)\n * @param {Object} options - additional sample playing options\n * @return {AudioNode} an audio node with a `stop` function\n * @example\n * var sample = player(ac, ).connect(ac.destination)\n * sample.start()\n * sample.start(5, { gain: 0.7 }) // name not required since is only one AudioBuffer\n * @example\n * var drums = player(ac, { snare: , kick: , ... }).connect(ac.destination)\n * drums.start('snare')\n * drums.start('snare', 0, { gain: 0.3 })\n */\n player.start = function (name, when, options) {\n // if only one buffer, reorder arguments\n if (player.buffer && name !== null) return player.start(null, name, when)\n \n var buffer = name ? player.buffers[name] : player.buffer\n if (!buffer) {\n console.warn('Buffer ' + name + ' not found.')\n return\n } else if (!connected) {\n console.warn('SamplePlayer not connected to any node.')\n return\n }\n \n var opts = options || EMPTY\n when = Math.max(ac.currentTime, when || 0)\n player.emit('start', when, name, opts)\n var node = createNode(name, buffer, opts)\n node.id = track(name, node)\n node.env.start(when)\n node.source.start(when)\n player.emit('started', when, node.id, node)\n if (opts.duration) node.stop(when + opts.duration)\n return node\n }\n \n // NOTE: start will be override so we can't copy the function reference\n // this is obviously not a good design, so this code will be gone soon.\n /**\n * An alias for `player.start`\n * @see player.start\n * @since 0.3.0\n */\n player.play = function (name, when, options) {\n return player.start(name, when, options)\n }\n \n /**\n * Stop some or all samples\n *\n * @param {Float} when - (Optional) an absolute time in seconds (or currentTime\n * if not specified)\n * @param {Array} nodes - (Optional) an array of nodes or nodes ids to stop\n * @return {Array} an array of ids of the stoped samples\n *\n * @example\n * var longSound = player(ac, ).connect(ac.destination)\n * longSound.start(ac.currentTime)\n * longSound.start(ac.currentTime + 1)\n * longSound.start(ac.currentTime + 2)\n * longSound.stop(ac.currentTime + 3) // stop the three sounds\n */\n player.stop = function (when, ids) {\n var node\n ids = ids || Object.keys(tracked)\n return ids.map(function (id) {\n node = tracked[id]\n if (!node) return null\n node.stop(when)\n return node.id\n })\n }\n /**\n * Connect the player to a destination node\n *\n * @param {AudioNode} destination - the destination node\n * @return {AudioPlayer} the player\n * @chainable\n * @example\n * var sample = player(ac, ).connect(ac.destination)\n */\n player.connect = function (dest) {\n connected = true\n out.connect(dest)\n return player\n }\n \n player.emit = function (event, when, obj, opts) {\n if (player.onevent) player.onevent(event, when, obj, opts)\n var fn = player['on' + event]\n if (fn) fn(when, obj, opts)\n }\n \n return player\n \n // =============== PRIVATE FUNCTIONS ============== //\n \n function track (name, node) {\n node.id = nextId++\n tracked[node.id] = node\n node.source.onended = function () {\n var now = ac.currentTime\n node.source.disconnect()\n node.env.disconnect()\n node.disconnect()\n player.emit('ended', now, node.id, node)\n }\n return node.id\n }\n \n function createNode (name, buffer, options) {\n var node = ac.createGain()\n node.gain.value = 0 // the envelope will control the gain\n node.connect(out)\n \n node.env = envelope(ac, options, opts)\n node.env.connect(node.gain)\n \n node.source = ac.createBufferSource()\n node.source.buffer = buffer\n node.source.connect(node)\n node.source.loop = options.loop || opts.loop\n node.source.playbackRate.value = centsToRate(options.cents || opts.cents)\n node.source.loopStart = options.loopStart || opts.loopStart\n node.source.loopEnd = options.loopEnd || opts.loopEnd\n node.stop = function (when) {\n var time = when || ac.currentTime\n player.emit('stop', time, name)\n var stopAt = node.env.stop(time)\n node.source.stop(stopAt)\n }\n return node\n }\n }\n \n function isNum (x) { return typeof x === 'number' }\n var PARAMS = ['attack', 'decay', 'sustain', 'release']\n function envelope (ac, options, opts) {\n var env = ADSR(ac)\n var adsr = options.adsr || opts.adsr\n PARAMS.forEach(function (name, i) {\n if (adsr) env[name] = adsr[i]\n else env[name] = options[name] || opts[name]\n })\n env.value.value = isNum(options.gain) ? options.gain\n : isNum(opts.gain) ? opts.gain : 1\n return env\n }\n \n /*\n * Get playback rate for a given pitch change (in cents)\n * Basic [math](http://www.birdsoft.demon.co.uk/music/samplert.htm):\n * f2 = f1 * 2^( C / 1200 )\n */\n function centsToRate (cents) { return cents ? Math.pow(2, cents / 1200) : 1 }\n \n module.exports = SamplePlayer\n \n },{\"adsr\":3}],14:[function(require,module,exports){\n 'use strict'\n \n var isArr = Array.isArray\n var isObj = function (o) { return o && typeof o === 'object' }\n var OPTS = {}\n \n module.exports = function (player) {\n /**\n * Schedule a list of events to be played at specific time.\n *\n * It supports three formats of events for the events list:\n *\n * - An array with [time, note]\n * - An array with [time, object]\n * - An object with { time: ?, [name|note|midi|key]: ? }\n *\n * @param {Float} time - an absolute time to start (or AudioContext's\n * currentTime if provided number is 0)\n * @param {Array} events - the events list.\n * @return {Array} an array of ids\n *\n * @example\n * // Event format: [time, note]\n * var piano = player(ac, ...).connect(ac.destination)\n * piano.schedule(0, [ [0, 'C2'], [0.5, 'C3'], [1, 'C4'] ])\n *\n * @example\n * // Event format: an object { time: ?, name: ? }\n * var drums = player(ac, ...).connect(ac.destination)\n * drums.schedule(0, [\n * { name: 'kick', time: 0 },\n * { name: 'snare', time: 0.5 },\n * { name: 'kick', time: 1 },\n * { name: 'snare', time: 1.5 }\n * ])\n */\n player.schedule = function (time, events) {\n var now = player.context.currentTime\n var when = time < now ? now : time\n player.emit('schedule', when, events)\n var t, o, note, opts\n return events.map(function (event) {\n if (!event) return null\n else if (isArr(event)) {\n t = event[0]; o = event[1]\n } else {\n t = event.time; o = event\n }\n \n if (isObj(o)) {\n note = o.name || o.key || o.note || o.midi || null\n opts = o\n } else {\n note = o\n opts = OPTS\n }\n \n return player.start(note, when + (t || 0), opts)\n })\n }\n return player\n }\n \n },{}],15:[function(require,module,exports){\n 'use strict'\n \n var REGEX = /^([a-gA-G])(#{1,}|b{1,}|x{1,}|)(-?\\d*)\\s*(.*)\\s*$/\n /**\n * A regex for matching note strings in scientific notation.\n *\n * @name regex\n * @function\n * @return {RegExp} the regexp used to parse the note name\n *\n * The note string should have the form `letter[accidentals][octave][element]`\n * where:\n *\n * - letter: (Required) is a letter from A to G either upper or lower case\n * - accidentals: (Optional) can be one or more `b` (flats), `#` (sharps) or `x` (double sharps).\n * They can NOT be mixed.\n * - octave: (Optional) a positive or negative integer\n * - element: (Optional) additionally anything after the duration is considered to\n * be the element name (for example: 'C2 dorian')\n *\n * The executed regex contains (by array index):\n *\n * - 0: the complete string\n * - 1: the note letter\n * - 2: the optional accidentals\n * - 3: the optional octave\n * - 4: the rest of the string (trimmed)\n *\n * @example\n * var parser = require('note-parser')\n * parser.regex.exec('c#4')\n * // => ['c#4', 'c', '#', '4', '']\n * parser.regex.exec('c#4 major')\n * // => ['c#4major', 'c', '#', '4', 'major']\n * parser.regex().exec('CMaj7')\n * // => ['CMaj7', 'C', '', '', 'Maj7']\n */\n function regex () { return REGEX }\n \n var SEMITONES = [0, 2, 4, 5, 7, 9, 11]\n /**\n * Parse a note name in scientific notation an return it's components,\n * and some numeric properties including midi number and frequency.\n *\n * @name parse\n * @function\n * @param {String} note - the note string to be parsed\n * @param {Boolean} isTonic - true if the note is the tonic of something.\n * If true, en extra tonicOf property is returned. It's false by default.\n * @param {Float} tunning - The frequency of A4 note to calculate frequencies.\n * By default it 440.\n * @return {Object} the parsed note name or null if not a valid note\n *\n * The parsed note name object will ALWAYS contains:\n * - letter: the uppercase letter of the note\n * - acc: the accidentals of the note (only sharps or flats)\n * - pc: the pitch class (letter + acc)\n * - step: s a numeric representation of the letter. It's an integer from 0 to 6\n * where 0 = C, 1 = D ... 6 = B\n * - alt: a numeric representation of the accidentals. 0 means no alteration,\n * positive numbers are for sharps and negative for flats\n * - chroma: a numeric representation of the pitch class. It's like midi for\n * pitch classes. 0 = C, 1 = C#, 2 = D ... It can have negative values: -1 = Cb.\n * Can detect pitch class enhramonics.\n *\n * If the note has octave, the parser object will contain:\n * - oct: the octave number (as integer)\n * - midi: the midi number\n * - freq: the frequency (using tuning parameter as base)\n *\n * If the parameter `isTonic` is set to true, the parsed object will contain:\n * - tonicOf: the rest of the string that follows note name (left and right trimmed)\n *\n * @example\n * var parse = require('note-parser').parse\n * parse('Cb4')\n * // => { letter: 'C', acc: 'b', pc: 'Cb', step: 0, alt: -1, chroma: -1,\n * oct: 4, midi: 59, freq: 246.94165062806206 }\n * // if no octave, no midi, no freq\n * parse('fx')\n * // => { letter: 'F', acc: '##', pc: 'F##', step: 3, alt: 2, chroma: 7 })\n */\n function parse (str, isTonic, tuning) {\n if (typeof str !== 'string') return null\n var m = REGEX.exec(str)\n if (!m || !isTonic && m[4]) return null\n \n var p = { letter: m[1].toUpperCase(), acc: m[2].replace(/x/g, '##') }\n p.pc = p.letter + p.acc\n p.step = (p.letter.charCodeAt(0) + 3) % 7\n p.alt = p.acc[0] === 'b' ? -p.acc.length : p.acc.length\n p.chroma = SEMITONES[p.step] + p.alt\n if (m[3]) {\n p.oct = +m[3]\n p.midi = p.chroma + 12 * (p.oct + 1)\n p.freq = midiToFreq(p.midi, tuning)\n }\n if (isTonic) p.tonicOf = m[4]\n return p\n }\n \n /**\n * Given a midi number, return its frequency\n * @param {Integer} midi - midi note number\n * @param {Float} tuning - (Optional) the A4 tuning (440Hz by default)\n * @return {Float} frequency in hertzs\n */\n function midiToFreq (midi, tuning) {\n return Math.pow(2, (midi - 69) / 12) * (tuning || 440)\n }\n \n var parser = { parse: parse, regex: regex, midiToFreq: midiToFreq }\n var FNS = ['letter', 'acc', 'pc', 'step', 'alt', 'chroma', 'oct', 'midi', 'freq']\n FNS.forEach(function (name) {\n parser[name] = function (src) {\n var p = parse(src)\n return p && (typeof p[name] !== 'undefined') ? p[name] : null\n }\n })\n \n module.exports = parser\n \n // extra API docs\n /**\n * Get midi of a note\n *\n * @name midi\n * @function\n * @param {String} note - the note name\n * @return {Integer} the midi number of the note or null if not a valid note\n * or the note does NOT contains octave\n * @example\n * var parser = require('note-parser')\n * parser.midi('A4') // => 69\n * parser.midi('A') // => null\n */\n /**\n * Get freq of a note in hertzs (in a well tempered 440Hz A4)\n *\n * @name freq\n * @function\n * @param {String} note - the note name\n * @return {Float} the freq of the number if hertzs or null if not valid note\n * or the note does NOT contains octave\n * @example\n * var parser = require('note-parser')\n * parser.freq('A4') // => 440\n * parser.freq('A') // => null\n */\n \n },{}]};\n\nlet modulesByID = {};\nfunction link(id) {\n if(!modulesByID[id]) {\n let _module = modulesByID[id] = { exports: {} };\n let _require = function(requiredName) {\n let requiredID = moduleDefs[id][1][requiredName];\n return link(requiredID || requiredName);\n };\n moduleDefs[id][0].call(_module.exports, _require, _module, _module.exports);\n }\n return modulesByID[id].exports;\n}\n\nlet soundfont = link(1)\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (soundfont);\n\n//# sourceURL=webpack:///./src/lib/soundfont-player.js?"); - -/***/ }), - -/***/ "./src/lib/tonal.min.js": -/*!******************************!*\ - !*** ./src/lib/tonal.min.js ***! - \******************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\nlet tonal = {};\n(function(n){\"use strict\";function t(n){\"string\"!=typeof n&&(n=\"\");var t=T.exec(n);return t?[t[1].toUpperCase(),t[2].replace(/x/g,\"##\"),t[3],t[4]]:null}function r(n,t){return n=Math.round(n),(!0===t?G:I)[n%12]+(Math.floor(n/12)-1)}function e(n,t){for(var r=[];t--;r[t]=t+n);return r}function m(n,t){for(var r=[];t--;r[t]=n-t);return r}function i(n,t){return null===n||null===t?[]:nan(t)})}function P(n){return o(n).filter(function(n,t,r){return 0===t||n!==r[t-1]})}function M(n){return\"string\"!=typeof n?An:_n[n]||(_n[n]=xn(n))}function a(n){var t=(n+1)%7;return t<0?7+t:t}function l(n,t){if(1===arguments.length)return function(t){return l(n,t)};var r=Kn(n),e=Qn(t);if(null===r||null===e)return null;var m=1===r.length?[r[0]+e[0]]:[r[0]+e[0],r[1]+e[1]];return mn(Un(m[0],m[1]))}function c(n,t){if(1===arguments.length)return function(t){return c(n,t)};var r=Kn(n);return null===r?null:mn(Un(r[0]+t))}function s(n,t){if(1===arguments.length)return function(t){return s(n,t)};var r=Kn(n),e=Kn(t);return null===e||null===r?null:e[0]-r[0]}function f(n,t){return 1===arguments.length?function(t){return l(t,n)}:l(t,n)}function d(n,t,r){var e=Qn(n),m=Qn(t);if(null===e||null===m)return null;var i=[e[0]+r*m[0],e[1]+r*m[1]];return Dn(Wn(i))}function p(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,1)}function b(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,-1)}function h(n,t){if(1===arguments.length)return function(t){return h(n,t)};var r=Kn(n),e=Kn(t);if(null===r||null===e||r.length!==e.length)return null;var m=1===r.length?[e[0]-r[0],-Math.floor(7*(e[0]-r[0])/12)]:[e[0]-r[0],e[1]-r[1]];return Dn(Wn(m))}function v(n,t){if(1===arguments.length)return function(t){return v(n,t)};var r=L(n),e=L(t);return null!==r.midi&&null!==e.midi?e.midi-r.midi:null!==r.chroma&&null!==e.chroma?(e.chroma-r.chroma+12)%12:null}function A(n){if(y(n))return n;if(!Array.isArray(n))return\"\";var t=[0,0,0,0,0,0,0,0,0,0,0,0];return n.map(nt).forEach(function(n){t[n]=1}),t.join(\"\")}function g(n){return et=et||i(2048,4095).map(function(n){return n.toString(2)}),\"number\"==typeof n?et.filter(function(t){return rt(t)===n}):et.slice()}function j(n,t){t=!1!==t;var r=A(n).split(\"\");return Mn(r.map(function(n,e){var m=u(e,r);return t&&\"0\"===m[0]?null:m.join(\"\")}))}function y(n){return mt.test(n)}function O(n){return y(n)?Mn(n.split(\"\").map(function(n,t){return\"1\"===n?it[t]:null})):[]}function x(n,t){return 1===arguments.length?function(t){return x(n,t)}:A(n)===A(t)}function _(n,t){return arguments.length>1?_(n)(t):(n=tt(n),function(t){return(t=tt(t))!==n&&(t&n)===t})}function z(n,t){return arguments.length>1?z(n)(t):(n=tt(n),function(t){return(t=tt(t))!==n&&(t|n)===t})}function q(n,t){return arguments.length>1?q(n)(t):(n=A(n),function(t){return\"1\"===n[nt(t)]})}function k(n,t){return 1===arguments.length?function(t){return k(n,t)}:t.filter(q(n))}function S(n,t){var r=D(n);return t=t||r[1],pt(t).map(l(r[0]))}function w(n){var t=D(n);return void 0!==Mt(t[1])}function D(n){if(\"string\"!=typeof n)return[\"\",\"\"];var t=n.indexOf(\" \"),r=R(n.substring(0,t))||R(n)||\"\",e=\"\"!==r?n.substring(r.length+1):n;return[r,e.length?e:\"\"]}function E(n,t){var r=C(n);return t=t||r[1],xt(t).intervals.map(l(r[0]))}function C(n){var r=t(n);return\"\"===r[0]?[\"\",n]:\"A\"===r[0]&&\"ug\"===r[3]?[\"\",\"aug\"]:St.test(r[2])?[r[0]+r[1],r[2]+r[3]]:[r[0]+r[1]+r[2],r[3]]}var $=\"C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B\".split(\" \"),F=function(n){return\"string\"!=typeof n?$.slice():$.filter(function(t){var r=t[1]||\" \";return-1!==n.indexOf(r)})},G=F(\" #\"),I=F(\" b\"),T=/^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\\d*)\\s*(.*)$/,B=Object.freeze({pc:null,name:null,step:null,alt:null,oct:null,octStr:null,chroma:null,midi:null,freq:null}),N=[0,2,4,5,7,9,11],L=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var r=t(n);if(\"\"===r[0]||\"\"!==r[3])return B;var e=r[0],m=r[1],i=r[2],u={letter:e,acc:m,octStr:i};return u.pc=u.letter+u.acc,u.name=u.pc+i,u.step=(u.letter.charCodeAt(0)+3)%7,u.alt=\"b\"===u.acc[0]?-u.acc.length:u.acc.length,u.oct=i.length?+i:null,u.chroma=(N[u.step]+u.alt+120)%12,u.midi=null!==u.oct?N[u.step]+u.alt+12*(u.oct+1):null,u.freq=J(u.midi),Object.freeze(u)}),R=function(n){return L(n).name},U=function(n){return L(n).pc},H=function(n){return L(n).midi||+n||null},J=function(n,t){return void 0===t&&(t=440),\"number\"==typeof n?Math.pow(2,(n-69)/12)*t:null},K=function(n){return L(n).freq||J(n)},Q=Math.log(2),V=Math.log(440),W=function(n){var t=12*(Math.log(n)-V)/Q+69;return Math.round(100*t)/100},X=function(n){return L(n).chroma},Y=function(n){return L(n).oct},Z=function(n){return\"CDEFGAB\"[n]},nn=function(n,t){return Array(t+1).join(n)},tn=function(n,t){return\"number\"!=typeof n?\"\":t(n)},rn=function(n){return tn(n,function(n){return n<0?nn(\"b\",-n):nn(\"#\",n)})},en=function(n,t){void 0===n&&(n={}),void 0===t&&(t=null);var r=t?Object.assign({},L(t),n):n,e=r.step,m=r.alt,i=r.oct,u=Z(e);if(!u)return null;var o=u+rn(m);return i||0===i?o+i:o},mn=en,un=function(n,t){var e=L(n),m=e.alt,i=e.chroma,u=e.midi;if(null===i)return null;var o=!1===t?m<0:m>0;return null===u?U(r(i,o)):r(u,o)},on=function(n){return un(n,!1)},Pn=Object.freeze({names:F,tokenize:t,props:L,name:R,pc:U,midi:H,midiToFreq:J,freq:K,freqToMidi:W,chroma:X,oct:Y,stepToLetter:Z,altToAcc:rn,from:en,build:mn,fromMidi:r,simplify:un,enharmonic:on}),Mn=function(n){return n.filter(function(n){return 0===n||n})},an=function(n){var t=H(n);return null!==t?t:H(n+\"-100\")},ln=function(n,t){void 0===t&&(t=Math.random);for(var r,e,m=n.length;m;)r=t()*m--|0,e=n[m],n[m]=n[r],n[r]=e;return n},cn=function(n){return 0===n.length?[[]]:cn(n.slice(1)).reduce(function(t,r){return t.concat(n.map(function(t,e){var m=r.slice();return m.splice(e,0,n[0]),m}))},[])},sn=Object.freeze({range:i,rotate:u,compact:Mn,sort:o,unique:P,shuffle:ln,permutations:cn}),fn=new RegExp(\"^([-+]?\\\\d+)(d{1,4}|m|M|P|A{1,4})|(AA|A|P|M|m|d|dd)([-+]?\\\\d+)$\"),dn=[0,2,4,5,7,9,11],pn=[0,1,2,3,4,5,6,5,4,3,2,1],bn=\"1P 2m 2M 3m 3M 4P 5P 6m 6M 7m 7M 8P\".split(\" \"),hn=function(n){return\"string\"!=typeof n?bn.slice():bn.filter(function(t){return-1!==n.indexOf(t[1])})},vn=function(n){var t=fn.exec(n);return null===t?null:t[1]?[t[1],t[2]]:[t[4],t[3]]},An=Object.freeze({name:null,num:null,q:null,step:null,alt:null,dir:null,type:null,simple:null,semitones:null,chroma:null}),gn=function(n,t){return Array(Math.abs(t)+1).join(n)},jn=function(n,t){return\"M\"===t&&\"M\"===n?0:\"P\"===t&&\"P\"===n?0:\"m\"===t&&\"M\"===n?-1:/^A+$/.test(t)?t.length:/^d+$/.test(t)?\"P\"===n?-t.length:-t.length-1:null},yn=function(n,t){return 0===t?\"M\"===n?\"M\":\"P\":-1===t&&\"M\"===n?\"m\":t>0?gn(\"A\",t):t<0?gn(\"d\",\"P\"===n?t:t+1):null},On=function(n){return(Math.abs(n)-1)%7},xn=function(n){var t=vn(n);if(null===t)return An;var r={num:+t[0],q:t[1]};return r.step=On(r.num),r.type=\"PMMPPMM\"[r.step],\"M\"===r.type&&\"P\"===r.q?An:(r.name=\"\"+r.num+r.q,r.dir=r.num<0?-1:1,r.simple=8===r.num||-8===r.num?r.num:r.dir*(r.step+1),r.alt=jn(r.type,r.q),r.oct=Math.floor((Math.abs(r.num)-1)/7),r.semitones=r.dir*(dn[r.step]+r.alt+12*r.oct),r.chroma=(r.dir*(dn[r.step]+r.alt)%12+12)%12,Object.freeze(r))},_n={},zn=function(n){return M(n).num},qn=function(n){return M(n).name},kn=function(n){return M(n).semitones},Sn=function(n){return M(n).chroma},wn=function(n){return\"string\"==typeof n&&(n=M(n).chroma),\"number\"==typeof n?pn[n%12]:null},Dn=function(n){void 0===n&&(n={});var t=n.num,r=n.step,e=n.alt,m=n.oct;void 0===m&&(m=1);var i=n.dir;if(void 0!==r&&(t=r+1+7*m),void 0===t)return null;var u=i<0?\"-\":\"\",o=\"PMMPPMM\"[On(t)];return u+t+yn(o,e)},En=function(n){var t=M(n);return t===An?null:t.simple+t.q},Cn=function(n){var t=M(n);if(t===An)return null;var r=(7-t.step)%7,e=\"P\"===t.type?-t.alt:-(t.alt+1);return Dn({step:r,alt:e,oct:t.oct,dir:t.dir})},$n=[1,2,2,3,3,4,5,5,6,6,7,7],Fn=\"P m M m M P d P m M m M\".split(\" \"),Gn=function(n){var t=n<0?-1:1,r=Math.abs(n),e=r%12,m=Math.floor(r/12);return t*($n[e]+7*m)+Fn[e]},In=Object.freeze({names:hn,tokenize:vn,props:M,num:zn,name:qn,semitones:kn,chroma:Sn,ic:wn,build:Dn,simplify:En,invert:Cn,fromSemitones:Gn}),Tn=[0,2,4,-1,1,3,5],Bn=function(n){return Math.floor(7*n/12)},Nn=Tn.map(Bn),Ln=function(n){var t=n.step,r=n.alt,e=n.oct,m=n.dir;void 0===m&&(m=1);var i=Tn[t]+7*r;return null===e?[m*i]:[m*i,m*(e-Nn[t]-4*r)]},Rn=[3,0,4,1,5,2,6],Un=function(n,t,r){var e=Rn[a(n)],m=Math.floor((n+1)/7);return void 0===t?{step:e,alt:m,dir:r}:{step:e,alt:m,oct:t+4*m+Nn[e],dir:r}},Hn=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}},Jn=function(n){return Hn(function(t){var r=n(t);return null===r.name?null:Ln(r)})},Kn=Jn(L),Qn=Jn(M),Vn=function(n){return 7*n[0]+12*n[1]<0},Wn=function(n){return Vn(n)?Un(-n[0],-n[1],-1):Un(n[0],n[1],1)},Xn=Object.freeze({transpose:l,trFifths:c,fifths:s,transposeBy:f,addIntervals:d,add:p,subtract:b,interval:h,semitones:v}),Yn={chromatic:[\"1P 2m 2M 3m 3M 4P 4A 5P 6m 6M 7m 7M\"],lydian:[\"1P 2M 3M 4A 5P 6M 7M\"],major:[\"1P 2M 3M 4P 5P 6M 7M\",[\"ionian\"]],mixolydian:[\"1P 2M 3M 4P 5P 6M 7m\",[\"dominant\"]],dorian:[\"1P 2M 3m 4P 5P 6M 7m\"],aeolian:[\"1P 2M 3m 4P 5P 6m 7m\",[\"minor\"]],phrygian:[\"1P 2m 3m 4P 5P 6m 7m\"],locrian:[\"1P 2m 3m 4P 5d 6m 7m\"],altered:[\"1P 2m 3m 3M 5d 6m 7m\",[\"super locrian\",\"diminished whole tone\",\"pomeroy\"]],iwato:[\"1P 2m 4P 5d 7m\"],hirajoshi:[\"1P 2M 3m 5P 6m\"],kumoijoshi:[\"1P 2m 4P 5P 6m\"],pelog:[\"1P 2m 3m 5P 6m\"],prometheus:[\"1P 2M 3M 4A 6M 7m\"],ritusen:[\"1P 2M 4P 5P 6M\"],scriabin:[\"1P 2m 3M 5P 6M\"],piongio:[\"1P 2M 4P 5P 6M 7m\"],augmented:[\"1P 2A 3M 5P 5A 7M\"],neopolitan:[\"1P 2m 3m 4P 5P 6m 7M\"],diminished:[\"1P 2M 3m 4P 5d 6m 6M 7M\"],egyptian:[\"1P 2M 4P 5P 7m\"],oriental:[\"1P 2m 3M 4P 5d 6M 7m\"],spanish:[\"1P 2m 3M 4P 5P 6m 7m\",[\"phrygian major\"]],flamenco:[\"1P 2m 3m 3M 4A 5P 7m\"],balinese:[\"1P 2m 3m 4P 5P 6m 7M\"],persian:[\"1P 2m 3M 4P 5d 6m 7M\"],bebop:[\"1P 2M 3M 4P 5P 6M 7m 7M\"],enigmatic:[\"1P 2m 3M 5d 6m 7m 7M\"],ichikosucho:[\"1P 2M 3M 4P 5d 5P 6M 7M\"],\"melodic minor\":[\"1P 2M 3m 4P 5P 6M 7M\"],\"melodic minor second mode\":[\"1P 2m 3m 4P 5P 6M 7m\"],\"lydian augmented\":[\"1P 2M 3M 4A 5A 6M 7M\"],\"lydian dominant\":[\"1P 2M 3M 4A 5P 6M 7m\",[\"lydian b7\"]],\"melodic minor fifth mode\":[\"1P 2M 3M 4P 5P 6m 7m\",[\"hindu\",\"mixolydian b6M\"]],\"locrian #2\":[\"1P 2M 3m 4P 5d 6m 7m\"],\"locrian major\":[\"1P 2M 3M 4P 5d 6m 7m\",[\"arabian\"]],\"major pentatonic\":[\"1P 2M 3M 5P 6M\",[\"pentatonic\"]],\"lydian pentatonic\":[\"1P 3M 4A 5P 7M\",[\"chinese\"]],\"mixolydian pentatonic\":[\"1P 3M 4P 5P 7m\",[\"indian\"]],\"locrian pentatonic\":[\"1P 3m 4P 5d 7m\",[\"minor seven flat five pentatonic\"]],\"minor pentatonic\":[\"1P 3m 4P 5P 7m\"],\"minor six pentatonic\":[\"1P 3m 4P 5P 6M\"],\"minor hexatonic\":[\"1P 2M 3m 4P 5P 7M\"],\"flat three pentatonic\":[\"1P 2M 3m 5P 6M\",[\"kumoi\"]],\"flat six pentatonic\":[\"1P 2M 3M 5P 6m\"],\"major flat two pentatonic\":[\"1P 2m 3M 5P 6M\"],\"whole tone pentatonic\":[\"1P 3M 5d 6m 7m\"],\"ionian pentatonic\":[\"1P 3M 4P 5P 7M\"],\"lydian #5P pentatonic\":[\"1P 3M 4A 5A 7M\"],\"lydian dominant pentatonic\":[\"1P 3M 4A 5P 7m\"],\"minor #7M pentatonic\":[\"1P 3m 4P 5P 7M\"],\"super locrian pentatonic\":[\"1P 3m 4d 5d 7m\"],\"in-sen\":[\"1P 2m 4P 5P 7m\"],\"vietnamese 1\":[\"1P 3m 4P 5P 6m\"],\"vietnamese 2\":[\"1P 3m 4P 5P 7m\"],\"prometheus neopolitan\":[\"1P 2m 3M 4A 6M 7m\"],\"major blues\":[\"1P 2M 3m 3M 5P 6M\"],\"minor blues\":[\"1P 3m 4P 5d 5P 7m\",[\"blues\"]],\"composite blues\":[\"1P 2M 3m 3M 4P 5d 5P 6M 7m\"],\"augmented heptatonic\":[\"1P 2A 3M 4P 5P 5A 7M\"],\"dorian #4\":[\"1P 2M 3m 4A 5P 6M 7m\"],\"lydian diminished\":[\"1P 2M 3m 4A 5P 6M 7M\"],\"whole tone\":[\"1P 2M 3M 4A 5A 7m\"],\"leading whole tone\":[\"1P 2M 3M 4A 5A 7m 7M\"],\"harmonic minor\":[\"1P 2M 3m 4P 5P 6m 7M\"],\"lydian minor\":[\"1P 2M 3M 4A 5P 6m 7m\"],\"neopolitan minor\":[\"1P 2m 3m 4P 5P 6m 7M\"],\"neopolitan major\":[\"1P 2m 3m 4P 5P 6M 7M\",[\"dorian b2\"]],\"neopolitan major pentatonic\":[\"1P 3M 4P 5d 7m\"],\"romanian minor\":[\"1P 2M 3m 5d 5P 6M 7m\"],\"double harmonic lydian\":[\"1P 2m 3M 4A 5P 6m 7M\"],\"harmonic major\":[\"1P 2M 3M 4P 5P 6m 7M\"],\"double harmonic major\":[\"1P 2m 3M 4P 5P 6m 7M\",[\"gypsy\"]],\"hungarian minor\":[\"1P 2M 3m 4A 5P 6m 7M\"],\"hungarian major\":[\"1P 2A 3M 4A 5P 6M 7m\"],\"spanish heptatonic\":[\"1P 2m 3m 3M 4P 5P 6m 7m\"],\"todi raga\":[\"1P 2m 3m 4A 5P 6m 7M\"],\"malkos raga\":[\"1P 3m 4P 6m 7m\"],\"kafi raga\":[\"1P 3m 3M 4P 5P 6M 7m 7M\"],\"purvi raga\":[\"1P 2m 3M 4P 4A 5P 6m 7M\"],\"bebop dominant\":[\"1P 2M 3M 4P 5P 6M 7m 7M\"],\"bebop minor\":[\"1P 2M 3m 3M 4P 5P 6M 7m\"],\"bebop major\":[\"1P 2M 3M 4P 5P 5A 6M 7M\"],\"bebop locrian\":[\"1P 2m 3m 4P 5d 5P 6m 7m\"],\"minor bebop\":[\"1P 2M 3m 4P 5P 6m 7m 7M\"],\"mystery #1\":[\"1P 2m 3M 5d 6m 7m\"],\"minor six diminished\":[\"1P 2M 3m 4P 5P 6m 6M 7M\"],\"ionian augmented\":[\"1P 2M 3M 4P 5A 6M 7M\"],\"lydian #9\":[\"1P 2m 3M 4A 5P 6M 7M\"],\"six tone symmetric\":[\"1P 2m 3M 4P 5A 6M\"]},Zn={M:[\"1P 3M 5P\",[\"Major\",\"\"]],M13:[\"1P 3M 5P 7M 9M 13M\",[\"maj13\",\"Maj13\"]],M6:[\"1P 3M 5P 13M\",[\"6\"]],M69:[\"1P 3M 5P 6M 9M\",[\"69\"]],M7add13:[\"1P 3M 5P 6M 7M 9M\"],M7b5:[\"1P 3M 5d 7M\"],M7b6:[\"1P 3M 6m 7M\"],M7b9:[\"1P 3M 5P 7M 9m\"],M7sus4:[\"1P 4P 5P 7M\"],M9:[\"1P 3M 5P 7M 9M\",[\"maj9\",\"Maj9\"]],M9b5:[\"1P 3M 5d 7M 9M\"],M9sus4:[\"1P 4P 5P 7M 9M\"],Madd9:[\"1P 3M 5P 9M\",[\"2\",\"add9\",\"add2\"]],Maj7:[\"1P 3M 5P 7M\",[\"maj7\",\"M7\"]],Mb5:[\"1P 3M 5d\"],Mb6:[\"1P 3M 13m\"],Msus2:[\"1P 2M 5P\",[\"add9no3\",\"sus2\"]],Msus4:[\"1P 4P 5P\",[\"sus\",\"sus4\"]],Maddb9:[\"1P 3M 5P 9m\"],m:[\"1P 3m 5P\"],m11:[\"1P 3m 5P 7m 9M 11P\",[\"_11\"]],m11b5:[\"1P 3m 7m 12d 2M 4P\",[\"h11\",\"_11b5\"]],m13:[\"1P 3m 5P 7m 9M 11P 13M\",[\"_13\"]],m6:[\"1P 3m 4P 5P 13M\",[\"_6\"]],m69:[\"1P 3m 5P 6M 9M\",[\"_69\"]],m7:[\"1P 3m 5P 7m\",[\"minor7\",\"_\",\"_7\"]],m7add11:[\"1P 3m 5P 7m 11P\",[\"m7add4\"]],m7b5:[\"1P 3m 5d 7m\",[\"half-diminished\",\"h7\",\"_7b5\"]],m9:[\"1P 3m 5P 7m 9M\",[\"_9\"]],m9b5:[\"1P 3m 7m 12d 2M\",[\"h9\",\"-9b5\"]],mMaj7:[\"1P 3m 5P 7M\",[\"mM7\",\"_M7\"]],mMaj7b6:[\"1P 3m 5P 6m 7M\",[\"mM7b6\"]],mM9:[\"1P 3m 5P 7M 9M\",[\"mMaj9\",\"-M9\"]],mM9b6:[\"1P 3m 5P 6m 7M 9M\",[\"mMaj9b6\"]],mb6M7:[\"1P 3m 6m 7M\"],mb6b9:[\"1P 3m 6m 9m\"],o:[\"1P 3m 5d\",[\"mb5\",\"dim\"]],o7:[\"1P 3m 5d 13M\",[\"diminished\",\"m6b5\",\"dim7\"]],o7M7:[\"1P 3m 5d 6M 7M\"],oM7:[\"1P 3m 5d 7M\"],sus24:[\"1P 2M 4P 5P\",[\"sus4add9\"]],madd4:[\"1P 3m 4P 5P\"],madd9:[\"1P 3m 5P 9M\"],4:[\"1P 4P 7m 10m\",[\"quartal\"]],5:[\"1P 5P\"],7:[\"1P 3M 5P 7m\",[\"Dominant\",\"Dom\"]],9:[\"1P 3M 5P 7m 9M\",[\"79\"]],11:[\"1P 5P 7m 9M 11P\"],13:[\"1P 3M 5P 7m 9M 13M\",[\"13_\"]],64:[\"5P 8P 10M\"],\"M#5\":[\"1P 3M 5A\",[\"augmented\",\"maj#5\",\"Maj#5\",\"+\",\"aug\"]],\"M#5add9\":[\"1P 3M 5A 9M\",[\"+add9\"]],\"M13#11\":[\"1P 3M 5P 7M 9M 11A 13M\",[\"maj13#11\",\"Maj13#11\",\"M13+4\",\"M13#4\"]],\"M6#11\":[\"1P 3M 5P 6M 11A\",[\"M6b5\",\"6#11\",\"6b5\"]],\"M69#11\":[\"1P 3M 5P 6M 9M 11A\"],\"M7#11\":[\"1P 3M 5P 7M 11A\",[\"maj7#11\",\"Maj7#11\",\"M7+4\",\"M7#4\"]],\"M7#5\":[\"1P 3M 5A 7M\",[\"maj7#5\",\"Maj7#5\",\"maj9#5\",\"M7+\"]],\"M7#5sus4\":[\"1P 4P 5A 7M\"],\"M7#9#11\":[\"1P 3M 5P 7M 9A 11A\"],\"M9#11\":[\"1P 3M 5P 7M 9M 11A\",[\"maj9#11\",\"Maj9#11\",\"M9+4\",\"M9#4\"]],\"M9#5\":[\"1P 3M 5A 7M 9M\",[\"Maj9#5\"]],\"M9#5sus4\":[\"1P 4P 5A 7M 9M\"],\"11b9\":[\"1P 5P 7m 9m 11P\"],\"13#11\":[\"1P 3M 5P 7m 9M 11A 13M\",[\"13+4\",\"13#4\"]],\"13#9\":[\"1P 3M 5P 7m 9A 13M\",[\"13#9_\"]],\"13#9#11\":[\"1P 3M 5P 7m 9A 11A 13M\"],\"13b5\":[\"1P 3M 5d 6M 7m 9M\"],\"13b9\":[\"1P 3M 5P 7m 9m 13M\"],\"13b9#11\":[\"1P 3M 5P 7m 9m 11A 13M\"],\"13no5\":[\"1P 3M 7m 9M 13M\"],\"13sus4\":[\"1P 4P 5P 7m 9M 13M\",[\"13sus\"]],\"69#11\":[\"1P 3M 5P 6M 9M 11A\"],\"7#11\":[\"1P 3M 5P 7m 11A\",[\"7+4\",\"7#4\",\"7#11_\",\"7#4_\"]],\"7#11b13\":[\"1P 3M 5P 7m 11A 13m\",[\"7b5b13\"]],\"7#5\":[\"1P 3M 5A 7m\",[\"+7\",\"7aug\",\"aug7\"]],\"7#5#9\":[\"1P 3M 5A 7m 9A\",[\"7alt\",\"7#5#9_\",\"7#9b13_\"]],\"7#5b9\":[\"1P 3M 5A 7m 9m\"],\"7#5b9#11\":[\"1P 3M 5A 7m 9m 11A\"],\"7#5sus4\":[\"1P 4P 5A 7m\"],\"7#9\":[\"1P 3M 5P 7m 9A\",[\"7#9_\"]],\"7#9#11\":[\"1P 3M 5P 7m 9A 11A\",[\"7b5#9\"]],\"7#9#11b13\":[\"1P 3M 5P 7m 9A 11A 13m\"],\"7#9b13\":[\"1P 3M 5P 7m 9A 13m\"],\"7add6\":[\"1P 3M 5P 7m 13M\",[\"67\",\"7add13\"]],\"7b13\":[\"1P 3M 7m 13m\"],\"7b5\":[\"1P 3M 5d 7m\"],\"7b6\":[\"1P 3M 5P 6m 7m\"],\"7b9\":[\"1P 3M 5P 7m 9m\"],\"7b9#11\":[\"1P 3M 5P 7m 9m 11A\",[\"7b5b9\"]],\"7b9#9\":[\"1P 3M 5P 7m 9m 9A\"],\"7b9b13\":[\"1P 3M 5P 7m 9m 13m\"],\"7b9b13#11\":[\"1P 3M 5P 7m 9m 11A 13m\",[\"7b9#11b13\",\"7b5b9b13\"]],\"7no5\":[\"1P 3M 7m\"],\"7sus4\":[\"1P 4P 5P 7m\",[\"7sus\"]],\"7sus4b9\":[\"1P 4P 5P 7m 9m\",[\"susb9\",\"7susb9\",\"7b9sus\",\"7b9sus4\",\"phryg\"]],\"7sus4b9b13\":[\"1P 4P 5P 7m 9m 13m\",[\"7b9b13sus4\"]],\"9#11\":[\"1P 3M 5P 7m 9M 11A\",[\"9+4\",\"9#4\",\"9#11_\",\"9#4_\"]],\"9#11b13\":[\"1P 3M 5P 7m 9M 11A 13m\",[\"9b5b13\"]],\"9#5\":[\"1P 3M 5A 7m 9M\",[\"9+\"]],\"9#5#11\":[\"1P 3M 5A 7m 9M 11A\"],\"9b13\":[\"1P 3M 7m 9M 13m\"],\"9b5\":[\"1P 3M 5d 7m 9M\"],\"9no5\":[\"1P 3M 7m 9M\"],\"9sus4\":[\"1P 4P 5P 7m 9M\",[\"9sus\"]],\"m#5\":[\"1P 3m 5A\",[\"m+\",\"mb6\"]],\"m11A 5\":[\"1P 3m 6m 7m 9M 11P\"],\"m7#5\":[\"1P 3m 6m 7m\"],\"m9#5\":[\"1P 3m 6m 7m 9M\"],\"+add#9\":[\"1P 3M 5A 9A\"]},nt=function(n){return X(n)||Sn(n)||0},tt=function(n){return parseInt(A(n),2)},rt=function(n){return n.replace(/0/g,\"\").length},et=null,mt=/^[01]{12}$/,it=\"1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M\".split(\" \"),ut=Object.freeze({chroma:A,chromas:g,modes:j,isChroma:y,intervals:O,isEqual:x,isSubsetOf:_,isSupersetOf:z,includes:q,filter:k}),ot=function(n){var t=Object.keys(n).sort(),r=[],e=[],m=function(n,t,m){r[n]=t,e[m]=e[m]||[],e[m].push(n)};t.forEach(function(t){var r=n[t][0].split(\" \"),e=n[t][1],i=A(r);m(t,r,i),e&&e.forEach(function(n){return m(n,r,i)})});var i=Object.keys(r).sort(),u=function(n){return r[n]};return u.names=function(n){return\"string\"==typeof n?(e[n]||[]).slice():(!0===n?i:t).slice()},u},Pt=function(n,t){var r=function(r){return n(r)||t(r)};return r.names=function(r){return n.names(r).concat(t.names(r))},r},Mt=ot(Yn),at=ot(Zn),lt=Pt(Mt,at),ct=Object.freeze({dictionary:ot,combine:Pt,scale:Mt,chord:at,pcset:lt}),st=Object.freeze({name:null,intervals:[],names:[],chroma:null,setnum:null}),ft=function(n,t){return function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=Mt(n);if(!t)return st;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=Mt.names(r.chroma),Object.freeze(r)},{}),dt=Mt.names,pt=function(n){var t=D(n);return ft(t[1]).intervals},bt=function(n){var t=pt(n),r=S(n);return j(t).map(function(n,e){var m=Mt.names(n)[0];if(m)return[r[e]||t[e],m]}).filter(function(n){return n})},ht=function(n){var t=_(pt(n));return at.names().filter(function(n){return t(at(n))})},vt=function(n){var t=Mn(n.map(U));if(!t.length)return t;var r=t[0],e=P(t);return u(e.indexOf(r),e)},At=function(n){if(!pt(n).length)return[];var t=z(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},gt=function(n){var t=_(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},jt=Object.freeze({props:ft,names:dt,intervals:pt,notes:S,exists:w,tokenize:D,modeNames:bt,chords:ht,toScale:vt,supersets:At,subsets:gt}),yt=at.names,Ot=Object.freeze({name:null,names:[],intervals:[],chroma:null,setnum:null}),xt=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=at(n);if(!t)return Ot;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=at.names(r.chroma),r}),_t=function(n){return xt(C(n)[1]).intervals},zt=function(n){return void 0!==at(C(n)[1])},qt=function(n){if(!_t(n).length)return[];var t=z(_t(n));return at.names().filter(function(n){return t(at(n))})},kt=function(n){var t=_(_t(n));return at.names().filter(function(n){return t(at(n))})},St=/^(6|64|7|9|11|13)$/,wt=Object.freeze({names:yt,props:xt,intervals:_t,notes:E,exists:zt,supersets:qt,subsets:kt,tokenize:C}),Dt=l,Et=h,Ct=L,$t=H,Ft=K,Gt=at,It=Mt;n.Array=sn,n.Note=Pn,n.Interval=In,n.Distance=Xn,n.Scale=jt,n.Chord=wt,n.PcSet=ut,n.Dictionary=ct,n.transpose=Dt,n.interval=Et,n.note=Ct,n.midi=$t,n.freq=Ft,n.chord=Gt,n.scale=It,Object.defineProperty(n,\"__esModule\",{value:!0})})(tonal);\n/* harmony default export */ __webpack_exports__[\"default\"] = (tonal);\n//# sourceMappingURL=tonal.min.js.map\n\n//# sourceURL=webpack:///./src/lib/tonal.min.js?"); - -/***/ }), - -/***/ "./src/loader/loader-node.js": -/*!***********************************!*\ - !*** ./src/loader/loader-node.js ***! - \***********************************/ -/*! exports provided: load */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(__dirname) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"load\", function() { return load; });\n/**\n * Load a file.\n * \n * * Style locator algorithm:\n * 1. If the path begins with http:// or https://, look at that URL\n * 2. If the path begins with . or / look in the filesystem or at a relative URL\n * 3. Otherwise, look in the styles folder in this repo (which will move to its\n * own repo eventually). For these built-in styles, the .play file extension\n * is not required.\n * \n * @param {string} path The path to the file to load.\n * @return {string} The content of the file.\n */\nasync function load(stylePath) {\n let isHTTP = stylePath.startsWith('http://') || stylePath.startsWith('https://');\n if (isHTTP) {\n console.log('TODO');\n return '';\n } else {\n let isRelative = stylePath.startsWith('.') || stylePath.startsWith('/');\n if (!isRelative) {\n let path = await Promise.resolve(/*! import() */).then(__webpack_require__.t.bind(null, /*! path */ \"path\", 7));\n stylePath = path.join(__dirname, '../../styles/', stylePath);\n if (!stylePath.endsWith('.play')) stylePath += '.play';\n }\n let fs = await Promise.resolve(/*! import() */).then(__webpack_require__.t.bind(null, /*! fs */ \"fs\", 7));\n return await (new Promise((resolve, reject) => {\n fs.readFile(stylePath, 'utf8', (err, data) => {\n if (err) {\n reject(err);\n } else {\n resolve(data);\n }\n });\n }));\n }\n}\n/* WEBPACK VAR INJECTION */}.call(this, \"src/loader\"))\n\n//# sourceURL=webpack:///./src/loader/loader-node.js?"); - -/***/ }), - -/***/ "./src/parser/grammar.js": -/*!*******************************!*\ - !*** ./src/parser/grammar.js ***! - \*******************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../lexer/lexer.js */ \"./src/lexer/lexer.js\");\n/* harmony import */ var _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../ast/ast_nodes.js */ \"./src/ast/ast_nodes.js\");\n// Generated automatically by nearley, version 2.13.0\n// http://github.com/Hardmath123/nearley\nfunction id(x) { return x[0]; }\n\n\n\nlet Lexer = _lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"];\nlet ParserRules = [\n {\"name\": \"main$macrocall$2\", \"symbols\": [\"TopLevelStatement\"]},\n {\"name\": \"main$macrocall$1$ebnf$1\", \"symbols\": []},\n {\"name\": \"main$macrocall$1$ebnf$1$subexpression$1\", \"symbols\": [\"_\", \"main$macrocall$2\"], \"postprocess\": d => d[1][0]},\n {\"name\": \"main$macrocall$1$ebnf$1\", \"symbols\": [\"main$macrocall$1$ebnf$1\", \"main$macrocall$1$ebnf$1$subexpression$1\"], \"postprocess\": function arrpush(d) {return d[0].concat([d[1]]);}},\n {\"name\": \"main$macrocall$1\", \"symbols\": [\"main$macrocall$2\", \"main$macrocall$1$ebnf$1\"], \"postprocess\": d => d[0].concat(d[1])},\n {\"name\": \"main\", \"symbols\": [\"_?\", \"main$macrocall$1\", \"_?\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"GlobalScope\"](d[1])},\n {\"name\": \"TopLevelStatement\", \"symbols\": [\"ConfigurationStatement\"], \"postprocess\": id},\n {\"name\": \"TopLevelStatement\", \"symbols\": [\"ImportStatement\"], \"postprocess\": id},\n {\"name\": \"TopLevelStatement\", \"symbols\": [\"TrackStatement\"], \"postprocess\": id},\n {\"name\": \"TopLevelStatement\", \"symbols\": [\"TrackCallStatement\"], \"postprocess\": id},\n {\"name\": \"ConfigurationStatement\", \"symbols\": [{\"literal\":\"@meta\"}, \"_?\", {\"literal\":\"{\"}, \"_?\", \"ConfigurationList\", \"_?\", {\"literal\":\"}\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"MetaStatement\"](d[4])},\n {\"name\": \"ConfigurationStatement\", \"symbols\": [{\"literal\":\"@options\"}, \"_?\", {\"literal\":\"{\"}, \"_?\", \"ConfigurationList\", \"_?\", {\"literal\":\"}\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"OptionsStatement\"](d[4])},\n {\"name\": \"ConfigurationList$macrocall$2\", \"symbols\": [\"FunctionCallExpression\"]},\n {\"name\": \"ConfigurationList$macrocall$1$ebnf$1\", \"symbols\": []},\n {\"name\": \"ConfigurationList$macrocall$1$ebnf$1$subexpression$1\", \"symbols\": [\"_\", \"ConfigurationList$macrocall$2\"], \"postprocess\": d => d[1][0]},\n {\"name\": \"ConfigurationList$macrocall$1$ebnf$1\", \"symbols\": [\"ConfigurationList$macrocall$1$ebnf$1\", \"ConfigurationList$macrocall$1$ebnf$1$subexpression$1\"], \"postprocess\": function arrpush(d) {return d[0].concat([d[1]]);}},\n {\"name\": \"ConfigurationList$macrocall$1\", \"symbols\": [\"ConfigurationList$macrocall$2\", \"ConfigurationList$macrocall$1$ebnf$1\"], \"postprocess\": d => d[0].concat(d[1])},\n {\"name\": \"ConfigurationList\", \"symbols\": [\"ConfigurationList$macrocall$1\"], \"postprocess\": id},\n {\"name\": \"ImportStatement\", \"symbols\": [{\"literal\":\"@import\"}, \"_\", \"StringLiteral\", \"_\", {\"literal\":\"as\"}, \"_\", \"Identifier\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"ImportStatement\"](d[2], d[6])},\n {\"name\": \"TrackStatement$macrocall$2\", \"symbols\": [\"TrackMember\"]},\n {\"name\": \"TrackStatement$macrocall$1$ebnf$1\", \"symbols\": []},\n {\"name\": \"TrackStatement$macrocall$1$ebnf$1$subexpression$1\", \"symbols\": [\"_\", \"TrackStatement$macrocall$2\"], \"postprocess\": d => d[1][0]},\n {\"name\": \"TrackStatement$macrocall$1$ebnf$1\", \"symbols\": [\"TrackStatement$macrocall$1$ebnf$1\", \"TrackStatement$macrocall$1$ebnf$1$subexpression$1\"], \"postprocess\": function arrpush(d) {return d[0].concat([d[1]]);}},\n {\"name\": \"TrackStatement$macrocall$1\", \"symbols\": [\"TrackStatement$macrocall$2\", \"TrackStatement$macrocall$1$ebnf$1\"], \"postprocess\": d => d[0].concat(d[1])},\n {\"name\": \"TrackStatement\", \"symbols\": [{\"literal\":\"@track\"}, \"_\", \"StringLiteral\", \"_\", {\"literal\":\"as\"}, \"_\", \"Identifier\", \"_?\", {\"literal\":\"{\"}, \"_?\", \"TrackStatement$macrocall$1\", \"_?\", {\"literal\":\"}\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"TrackStatement\"]({instrument: d[2], identifier: d[6], members: d[10]})},\n {\"name\": \"TrackMember\", \"symbols\": [\"FunctionCallExpression\"], \"postprocess\": id},\n {\"name\": \"TrackMember\", \"symbols\": [\"PatternStatement\"], \"postprocess\": id},\n {\"name\": \"TrackMember\", \"symbols\": [\"PatternCallExpression\"], \"postprocess\": id},\n {\"name\": \"TrackCallStatement\", \"symbols\": [{\"literal\":\"@track\"}, \"_?\", {\"literal\":\"(\"}, \"_?\", \"Identifier\", {\"literal\":\".\"}, \"Identifier\", \"_?\", {\"literal\":\")\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"TrackCall\"]({import: d[4], track: d[6]})},\n {\"name\": \"PatternStatement\", \"symbols\": [{\"literal\":\"@pattern\"}, \"_\", \"Identifier\", \"_\", \"PatternConditional\", \"_?\", \"PatternExpression\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"PatternStatement\"]({identifier: d[2], expression: d[6], condition: d[4]})},\n {\"name\": \"PatternStatement\", \"symbols\": [{\"literal\":\"@pattern\"}, \"_\", \"Identifier\", \"_\", \"PatternExpression\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"PatternStatement\"]({identifier: d[2], expression: d[4]})},\n {\"name\": \"PatternConditional\", \"symbols\": [{\"literal\":\"if\"}, \"_?\", {\"literal\":\"(\"}, \"_?\", \"FunctionCallArgument\", \"_?\", {\"literal\":\")\"}], \"postprocess\": d => d[4]},\n {\"name\": \"PatternExpression\", \"symbols\": [\"PatternExpression_NoJoin\"], \"postprocess\": id},\n {\"name\": \"PatternExpression\", \"symbols\": [\"JoinedPatternExpression\"], \"postprocess\": id},\n {\"name\": \"PatternExpression_NoJoin\", \"symbols\": [\"PatternExpressionGroup\"], \"postprocess\": id},\n {\"name\": \"PatternExpression_NoJoin\", \"symbols\": [\"BeatGroupLiteral\"], \"postprocess\": id},\n {\"name\": \"PatternExpression_NoJoin\", \"symbols\": [\"DrumBeatGroupLiteral\"], \"postprocess\": id},\n {\"name\": \"PatternExpression_NoJoin\", \"symbols\": [\"FunctionCallExpression\"], \"postprocess\": id},\n {\"name\": \"PatternExpression_NoJoin\", \"symbols\": [\"PatternCallExpression\"], \"postprocess\": id},\n {\"name\": \"PatternExpressionGroup$macrocall$2\", \"symbols\": [\"PatternExpression\"]},\n {\"name\": \"PatternExpressionGroup$macrocall$1$ebnf$1\", \"symbols\": []},\n {\"name\": \"PatternExpressionGroup$macrocall$1$ebnf$1$subexpression$1\", \"symbols\": [\"_\", \"PatternExpressionGroup$macrocall$2\"], \"postprocess\": d => d[1][0]},\n {\"name\": \"PatternExpressionGroup$macrocall$1$ebnf$1\", \"symbols\": [\"PatternExpressionGroup$macrocall$1$ebnf$1\", \"PatternExpressionGroup$macrocall$1$ebnf$1$subexpression$1\"], \"postprocess\": function arrpush(d) {return d[0].concat([d[1]]);}},\n {\"name\": \"PatternExpressionGroup$macrocall$1\", \"symbols\": [\"PatternExpressionGroup$macrocall$2\", \"PatternExpressionGroup$macrocall$1$ebnf$1\"], \"postprocess\": d => d[0].concat(d[1])},\n {\"name\": \"PatternExpressionGroup\", \"symbols\": [{\"literal\":\"{\"}, \"_?\", \"PatternExpressionGroup$macrocall$1\", \"_?\", {\"literal\":\"}\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"PatternExpressionGroup\"](d[2])},\n {\"name\": \"PatternCallExpression\", \"symbols\": [{\"literal\":\"@pattern\"}, \"_?\", {\"literal\":\"(\"}, \"_?\", \"Identifier\", \"_?\", {\"literal\":\")\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"PatternCall\"]({pattern: d[4]})},\n {\"name\": \"PatternCallExpression\", \"symbols\": [{\"literal\":\"@pattern\"}, \"_?\", {\"literal\":\"(\"}, \"_?\", \"Identifier\", {\"literal\":\".\"}, \"Identifier\", \"_?\", {\"literal\":\")\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"PatternCall\"]({track: d[4], pattern: d[6]})},\n {\"name\": \"PatternCallExpression\", \"symbols\": [{\"literal\":\"@pattern\"}, \"_?\", {\"literal\":\"(\"}, \"_?\", \"Identifier\", {\"literal\":\".\"}, \"Identifier\", {\"literal\":\".\"}, \"Identifier\", \"_?\", {\"literal\":\")\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"PatternCall\"]({import: d[4], track: d[6], pattern: d[8]})},\n {\"name\": \"JoinedPatternExpression$macrocall$2\", \"symbols\": [\"PatternExpression_NoJoin\"]},\n {\"name\": \"JoinedPatternExpression$macrocall$3\", \"symbols\": [{\"literal\":\"&\"}]},\n {\"name\": \"JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$1\", \"symbols\": [\"_?\", \"JoinedPatternExpression$macrocall$3\", \"_?\", \"JoinedPatternExpression$macrocall$2\"], \"postprocess\": d => d[3][0]},\n {\"name\": \"JoinedPatternExpression$macrocall$1$ebnf$1\", \"symbols\": [\"JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$1\"]},\n {\"name\": \"JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$2\", \"symbols\": [\"_?\", \"JoinedPatternExpression$macrocall$3\", \"_?\", \"JoinedPatternExpression$macrocall$2\"], \"postprocess\": d => d[3][0]},\n {\"name\": \"JoinedPatternExpression$macrocall$1$ebnf$1\", \"symbols\": [\"JoinedPatternExpression$macrocall$1$ebnf$1\", \"JoinedPatternExpression$macrocall$1$ebnf$1$subexpression$2\"], \"postprocess\": function arrpush(d) {return d[0].concat([d[1]]);}},\n {\"name\": \"JoinedPatternExpression$macrocall$1\", \"symbols\": [\"JoinedPatternExpression$macrocall$2\", \"JoinedPatternExpression$macrocall$1$ebnf$1\"], \"postprocess\": d => d[0].concat(d[1])},\n {\"name\": \"JoinedPatternExpression\", \"symbols\": [\"JoinedPatternExpression$macrocall$1\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"JoinedPatternExpression\"](d[0])},\n {\"name\": \"FunctionCallExpression$macrocall$2\", \"symbols\": [\"FunctionCallArgument\"]},\n {\"name\": \"FunctionCallExpression$macrocall$1$ebnf$1\", \"symbols\": []},\n {\"name\": \"FunctionCallExpression$macrocall$1$ebnf$1$subexpression$1\", \"symbols\": [\"_\", \"FunctionCallExpression$macrocall$2\"], \"postprocess\": d => d[1][0]},\n {\"name\": \"FunctionCallExpression$macrocall$1$ebnf$1\", \"symbols\": [\"FunctionCallExpression$macrocall$1$ebnf$1\", \"FunctionCallExpression$macrocall$1$ebnf$1$subexpression$1\"], \"postprocess\": function arrpush(d) {return d[0].concat([d[1]]);}},\n {\"name\": \"FunctionCallExpression$macrocall$1\", \"symbols\": [\"FunctionCallExpression$macrocall$2\", \"FunctionCallExpression$macrocall$1$ebnf$1\"], \"postprocess\": d => d[0].concat(d[1])},\n {\"name\": \"FunctionCallExpression\", \"symbols\": [\"Identifier\", \"_?\", {\"literal\":\"(\"}, \"_?\", \"FunctionCallExpression$macrocall$1\", \"_?\", {\"literal\":\")\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"FunctionCall\"](d[0], d[4])},\n {\"name\": \"FunctionCallExpression\", \"symbols\": [\"Identifier\", \"_?\", {\"literal\":\"(\"}, {\"literal\":\")\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"FunctionCall\"](d[0], [])},\n {\"name\": \"FunctionCallArgument\", \"symbols\": [\"NumericExpression\"], \"postprocess\": id},\n {\"name\": \"FunctionCallArgument\", \"symbols\": [\"StringLiteral\"], \"postprocess\": id},\n {\"name\": \"FunctionCallArgument\", \"symbols\": [\"BooleanLiteral\"], \"postprocess\": id},\n {\"name\": \"FunctionCallArgument\", \"symbols\": [\"PatternExpression\"], \"postprocess\": id},\n {\"name\": \"FunctionCallArgument\", \"symbols\": [\"BL_PP_Anchor\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"AnchorArgument\"](d[0])},\n {\"name\": \"FunctionCallArgument\", \"symbols\": [{\"literal\":\"not\"}, \"_\", \"FunctionCallArgument\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"BooleanNot\"](d[2])},\n {\"name\": \"FunctionCallArgument\", \"symbols\": [\"FunctionCallArgument\", \"_\", {\"literal\":\"and\"}, \"_\", \"FunctionCallArgument\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"BooleanAnd\"](d[0], d[4])},\n {\"name\": \"FunctionCallArgument\", \"symbols\": [\"FunctionCallArgument\", \"_\", {\"literal\":\"or\"}, \"_\", \"FunctionCallArgument\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"BooleanOr\"](d[0], d[4])},\n {\"name\": \"BeatGroupLiteral\", \"symbols\": [{\"literal\":\"<\"}, \"_?\", \"MeasureGroup\", \"_?\", {\"literal\":\">\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"BeatGroupLiteral\"](d[2])},\n {\"name\": \"MeasureGroup$macrocall$2\", \"symbols\": [\"Measure\"]},\n {\"name\": \"MeasureGroup$macrocall$3\", \"symbols\": [{\"literal\":\"|\"}]},\n {\"name\": \"MeasureGroup$macrocall$1$ebnf$1\", \"symbols\": []},\n {\"name\": \"MeasureGroup$macrocall$1$ebnf$1$subexpression$1\", \"symbols\": [\"_?\", \"MeasureGroup$macrocall$3\", \"_?\", \"MeasureGroup$macrocall$2\"], \"postprocess\": d => d[3][0]},\n {\"name\": \"MeasureGroup$macrocall$1$ebnf$1\", \"symbols\": [\"MeasureGroup$macrocall$1$ebnf$1\", \"MeasureGroup$macrocall$1$ebnf$1$subexpression$1\"], \"postprocess\": function arrpush(d) {return d[0].concat([d[1]]);}},\n {\"name\": \"MeasureGroup$macrocall$1\", \"symbols\": [\"MeasureGroup$macrocall$2\", \"MeasureGroup$macrocall$1$ebnf$1\"], \"postprocess\": d => d[0].concat(d[1])},\n {\"name\": \"MeasureGroup\", \"symbols\": [\"MeasureGroup$macrocall$1\"], \"postprocess\": id},\n {\"name\": \"Measure$macrocall$2\", \"symbols\": [\"MelodicBeatLiteral\"]},\n {\"name\": \"Measure$macrocall$1$ebnf$1\", \"symbols\": []},\n {\"name\": \"Measure$macrocall$1$ebnf$1$subexpression$1\", \"symbols\": [\"_\", \"Measure$macrocall$2\"], \"postprocess\": d => d[1][0]},\n {\"name\": \"Measure$macrocall$1$ebnf$1\", \"symbols\": [\"Measure$macrocall$1$ebnf$1\", \"Measure$macrocall$1$ebnf$1$subexpression$1\"], \"postprocess\": function arrpush(d) {return d[0].concat([d[1]]);}},\n {\"name\": \"Measure$macrocall$1\", \"symbols\": [\"Measure$macrocall$2\", \"Measure$macrocall$1$ebnf$1\"], \"postprocess\": d => d[0].concat(d[1])},\n {\"name\": \"Measure\", \"symbols\": [\"Measure$macrocall$1\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"Measure\"](d[0])},\n {\"name\": \"MelodicBeatLiteral\", \"symbols\": [\"BL_TimePart\", {\"literal\":\":\"}, \"BL_PitchPart\", {\"literal\":\":\"}, \"BL_OctavePart\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"]({time: d[0], pitch: d[2], octave: d[4]})},\n {\"name\": \"MelodicBeatLiteral\", \"symbols\": [{\"literal\":\":\"}, \"BL_PitchPart\", {\"literal\":\":\"}, \"BL_OctavePart\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"]({pitch: d[1], octave: d[3]})},\n {\"name\": \"MelodicBeatLiteral\", \"symbols\": [\"BL_TimePart\", {\"literal\":\":\"}, \"BL_PitchPart\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"]({time: d[0], pitch: d[2]})},\n {\"name\": \"MelodicBeatLiteral\", \"symbols\": [{\"literal\":\":\"}, \"BL_PitchPart\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"MelodicBeatLiteral\"]({pitch: d[1]})},\n {\"name\": \"MelodicBeatLiteral\", \"symbols\": [\"DrumBeatLiteral\"], \"postprocess\": id},\n {\"name\": \"BL_TimePart\", \"symbols\": [\"NumericExpression\"], \"postprocess\": d => ({time: d[0]})},\n {\"name\": \"BL_TimePart\", \"symbols\": [\"BL_TP_Flag\"], \"postprocess\": d => ({time: 'auto', flag: d[0]})},\n {\"name\": \"BL_TimePart\", \"symbols\": [\"NumericExpression\", \"BL_TP_Flag\"], \"postprocess\": d => ({time: d[0], flag: d[1]})},\n {\"name\": \"BL_TP_Flag\", \"symbols\": [{\"literal\":\"s\"}], \"postprocess\": d => 'STACCATO'},\n {\"name\": \"BL_TP_Flag\", \"symbols\": [{\"literal\":\"a\"}], \"postprocess\": d => 'ACCENTED'},\n {\"name\": \"BL_PitchPart\", \"symbols\": [\"BL_PP_Degree\"], \"postprocess\": id},\n {\"name\": \"BL_PitchPart\", \"symbols\": [\"BL_PP_Chord\"], \"postprocess\": id},\n {\"name\": \"BL_PP_Degree\", \"symbols\": [\"NumberLiteral\"], \"postprocess\": d => ({degree: d[0]})},\n {\"name\": \"BL_PP_Degree\", \"symbols\": [\"BL_PP_Anchor\"], \"postprocess\": d => ({anchor: d[0], degree: 1})},\n {\"name\": \"BL_PP_Degree\", \"symbols\": [\"BL_PP_Anchor\", \"NumberLiteral\"], \"postprocess\": d => ({anchor: d[0], degree: d[1]})},\n {\"name\": \"BL_PP_Chord\", \"symbols\": [{\"literal\":\"c\"}], \"postprocess\": d => ({chord: true, degree: 1})},\n {\"name\": \"BL_PP_Chord\", \"symbols\": [\"BL_PP_Degree\", {\"literal\":\"c\"}], \"postprocess\": d => ({chord: true, anchor: d[0].anchor, degree: d[0].degree})},\n {\"name\": \"BL_PP_Chord\", \"symbols\": [{\"literal\":\"c\"}, \"BL_PP_Roll\"], \"postprocess\": d => ({chord: true, roll: d[1], degree: 1})},\n {\"name\": \"BL_PP_Chord\", \"symbols\": [\"BL_PP_Degree\", {\"literal\":\"c\"}, \"BL_PP_Roll\"], \"postprocess\": d => ({chord: true, roll: d[2], anchor: d[0].anchor, degree: d[0].degree})},\n {\"name\": \"BL_PP_Anchor\", \"symbols\": [{\"literal\":\"k\"}], \"postprocess\": d => 'KEY'},\n {\"name\": \"BL_PP_Anchor\", \"symbols\": [{\"literal\":\"n\"}], \"postprocess\": d => 'NEXT'},\n {\"name\": \"BL_PP_Anchor\", \"symbols\": [{\"literal\":\"s\"}], \"postprocess\": d => 'STEP'},\n {\"name\": \"BL_PP_Anchor\", \"symbols\": [{\"literal\":\"a\"}], \"postprocess\": d => 'ARPEGGIATE'},\n {\"name\": \"BL_PP_Roll\", \"symbols\": [{\"literal\":\"r\"}], \"postprocess\": d => 'ROLL_UP'},\n {\"name\": \"BL_PP_Roll\", \"symbols\": [{\"literal\":\"r\"}, {\"literal\":\"d\"}], \"postprocess\": d => 'ROLL_DOWN'},\n {\"name\": \"BL_OctavePart\", \"symbols\": [\"NumberLiteral\"], \"postprocess\": id},\n {\"name\": \"DrumBeatGroupLiteral\", \"symbols\": [\"StringLiteral\", \"_?\", \"BeatGroupLiteral\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"DrumBeatGroupLiteral\"](d[0], d[2])},\n {\"name\": \"DrumBeatGroupLiteral\", \"symbols\": [\"StringLiteral\", \"_?\", \"FunctionCallExpression\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"DrumBeatGroupLiteral\"](d[0], d[2])},\n {\"name\": \"DrumBeatLiteral\", \"symbols\": [\"NumberLiteral\"], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"DrumBeatLiteral\"]({time: d[0]})},\n {\"name\": \"DrumBeatLiteral\", \"symbols\": [\"NumberLiteral\", {\"literal\":\"a\"}], \"postprocess\": d => new _ast_ast_nodes_js__WEBPACK_IMPORTED_MODULE_1__[\"DrumBeatLiteral\"]({time: d[0], accented: true})},\n {\"name\": \"NumericExpression\", \"symbols\": [\"NE_addsub\"], \"postprocess\": id},\n {\"name\": \"NE_parens\", \"symbols\": [{\"literal\":\"(\"}, \"NE_addsub\", {\"literal\":\")\"}], \"postprocess\": d => d[1]},\n {\"name\": \"NE_parens\", \"symbols\": [\"NumberLiteral\"], \"postprocess\": id},\n {\"name\": \"NE_muldiv\", \"symbols\": [\"NE_muldiv\", {\"literal\":\"*\"}, \"NE_parens\"], \"postprocess\": d => (d[0] * d[2])},\n {\"name\": \"NE_muldiv\", \"symbols\": [\"NE_muldiv\", {\"literal\":\"/\"}, \"NE_parens\"], \"postprocess\": d => (d[0] / d[2])},\n {\"name\": \"NE_muldiv\", \"symbols\": [\"NE_parens\"], \"postprocess\": id},\n {\"name\": \"NE_addsub\", \"symbols\": [\"NE_addsub\", {\"literal\":\"+\"}, \"NE_muldiv\"], \"postprocess\": d => (d[0] + d[2])},\n {\"name\": \"NE_addsub\", \"symbols\": [\"NE_addsub\", {\"literal\":\"-\"}, \"NE_muldiv\"], \"postprocess\": d => (d[0] - d[2])},\n {\"name\": \"NE_addsub\", \"symbols\": [\"NE_muldiv\"], \"postprocess\": id},\n {\"name\": \"Identifier\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"identifier\") ? {type: \"identifier\"} : identifier)], \"postprocess\": d => d[0].value},\n {\"name\": \"NumberLiteral\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"number\") ? {type: \"number\"} : number)], \"postprocess\": d => Number(d[0].value)},\n {\"name\": \"NumberLiteral\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"beat_number\") ? {type: \"beat_number\"} : beat_number)], \"postprocess\": d => Number(d[0].value)},\n {\"name\": \"BooleanLiteral\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"boolean\") ? {type: \"boolean\"} : boolean)], \"postprocess\": d => Boolean(d[0].value)},\n {\"name\": \"StringLiteral\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"quoted_string\") ? {type: \"quoted_string\"} : quoted_string)], \"postprocess\": d => d[0].value.slice(1, -1)},\n {\"name\": \"_?$ebnf$1\", \"symbols\": [\"_\"], \"postprocess\": id},\n {\"name\": \"_?$ebnf$1\", \"symbols\": [], \"postprocess\": function(d) {return null;}},\n {\"name\": \"_?\", \"symbols\": [\"_?$ebnf$1\"], \"postprocess\": () => null},\n {\"name\": \"_\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"ws\") ? {type: \"ws\"} : ws)], \"postprocess\": () => null},\n {\"name\": \"_\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"beat_ws\") ? {type: \"beat_ws\"} : beat_ws)], \"postprocess\": () => null},\n {\"name\": \"_$ebnf$1\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"ws\") ? {type: \"ws\"} : ws)], \"postprocess\": id},\n {\"name\": \"_$ebnf$1\", \"symbols\": [], \"postprocess\": function(d) {return null;}},\n {\"name\": \"_$ebnf$2$subexpression$1$ebnf$1\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"ws\") ? {type: \"ws\"} : ws)], \"postprocess\": id},\n {\"name\": \"_$ebnf$2$subexpression$1$ebnf$1\", \"symbols\": [], \"postprocess\": function(d) {return null;}},\n {\"name\": \"_$ebnf$2$subexpression$1\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"comment\") ? {type: \"comment\"} : comment), \"_$ebnf$2$subexpression$1$ebnf$1\"]},\n {\"name\": \"_$ebnf$2\", \"symbols\": [\"_$ebnf$2$subexpression$1\"]},\n {\"name\": \"_$ebnf$2$subexpression$2$ebnf$1\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"ws\") ? {type: \"ws\"} : ws)], \"postprocess\": id},\n {\"name\": \"_$ebnf$2$subexpression$2$ebnf$1\", \"symbols\": [], \"postprocess\": function(d) {return null;}},\n {\"name\": \"_$ebnf$2$subexpression$2\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"comment\") ? {type: \"comment\"} : comment), \"_$ebnf$2$subexpression$2$ebnf$1\"]},\n {\"name\": \"_$ebnf$2\", \"symbols\": [\"_$ebnf$2\", \"_$ebnf$2$subexpression$2\"], \"postprocess\": function arrpush(d) {return d[0].concat([d[1]]);}},\n {\"name\": \"_\", \"symbols\": [\"_$ebnf$1\", \"_$ebnf$2\"], \"postprocess\": () => null},\n {\"name\": \"_$ebnf$3\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"beat_ws\") ? {type: \"beat_ws\"} : beat_ws)], \"postprocess\": id},\n {\"name\": \"_$ebnf$3\", \"symbols\": [], \"postprocess\": function(d) {return null;}},\n {\"name\": \"_$ebnf$4$subexpression$1$ebnf$1\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"beat_ws\") ? {type: \"beat_ws\"} : beat_ws)], \"postprocess\": id},\n {\"name\": \"_$ebnf$4$subexpression$1$ebnf$1\", \"symbols\": [], \"postprocess\": function(d) {return null;}},\n {\"name\": \"_$ebnf$4$subexpression$1\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"comment\") ? {type: \"comment\"} : comment), \"_$ebnf$4$subexpression$1$ebnf$1\"]},\n {\"name\": \"_$ebnf$4\", \"symbols\": [\"_$ebnf$4$subexpression$1\"]},\n {\"name\": \"_$ebnf$4$subexpression$2$ebnf$1\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"beat_ws\") ? {type: \"beat_ws\"} : beat_ws)], \"postprocess\": id},\n {\"name\": \"_$ebnf$4$subexpression$2$ebnf$1\", \"symbols\": [], \"postprocess\": function(d) {return null;}},\n {\"name\": \"_$ebnf$4$subexpression$2\", \"symbols\": [(_lexer_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].has(\"comment\") ? {type: \"comment\"} : comment), \"_$ebnf$4$subexpression$2$ebnf$1\"]},\n {\"name\": \"_$ebnf$4\", \"symbols\": [\"_$ebnf$4\", \"_$ebnf$4$subexpression$2\"], \"postprocess\": function arrpush(d) {return d[0].concat([d[1]]);}},\n {\"name\": \"_\", \"symbols\": [\"_$ebnf$3\", \"_$ebnf$4\"], \"postprocess\": () => null}\n];\nlet ParserStart = \"main\";\n/* harmony default export */ __webpack_exports__[\"default\"] = ({ Lexer, ParserRules, ParserStart });\n\n\n//# sourceURL=webpack:///./src/parser/grammar.js?"); - -/***/ }), - -/***/ "./src/parser/parser.js": -/*!******************************!*\ - !*** ./src/parser/parser.js ***! - \******************************/ -/*! exports provided: string_to_ast, parse */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"string_to_ast\", function() { return string_to_ast; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"parse\", function() { return parse; });\n/* harmony import */ var _lib_nearley_nearley_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../lib/nearley/nearley.js */ \"./src/lib/nearley/nearley.js\");\n/* harmony import */ var _grammar_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./grammar.js */ \"./src/parser/grammar.js\");\n\n\n/**\n * Parses a string into a set of possible abstract systax trees (ASTs) trees of\n * objects representing the syntax of the file.\n * @param {string} data The string to parse\n * @return {Promise..} A promise that resolves to an array\n * of parsings, each of which is an AST. (Ideally there should be 1 parsing.)\n *\n * See ast_nodes.js or the grammar itself for an idea of what the nodes in the\n * tree might look like.\n * @private\n */\nlet string_to_ast = function string_to_ast(data) {\n // Create a Parser object from our grammar.\n // (I don't think you can reset the parser so make a new one each time)\n const parser = new _lib_nearley_nearley_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Parser(_lib_nearley_nearley_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Grammar.fromCompiled(_grammar_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"]));\n \n return new Promise(function(resolve, reject) {\n try {\n parser.feed(data);\n } catch(err) {\n // Because tabs screw up the formatting of SyntaxError messages.\n err.message = err.message.replace(/\\t/g, ' ');\n reject(err);\n }\n resolve(parser.results);\n });\n};\n\n/**\n * Parse a string into an Abstract Syntax Tree (AST) -- a tree of objects\n * representing the syntax of the file.\n * @param {string} data The string to parse\n * @return {Promise.} The Abstract Systax Tree (AST).\n */\n let parse = function parse(data) {\n return new Promise(function(resolve, reject) {\n string_to_ast(data)\n .then(parses => {\n if(!parses.length) {\n throw new SyntaxError('Something went wrong, input not parseable.');\n }\n resolve(parses[0]);\n });\n });\n };\n\n\n//# sourceURL=webpack:///./src/parser/parser.js?"); - -/***/ }), - -/***/ "./src/parser/test/test.js": -/*!*********************************!*\ - !*** ./src/parser/test/test.js ***! - \*********************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _loader_loader_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../loader/loader.js */ \"./src/loader/loader-node.js\");\n/* harmony import */ var _parser_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../parser.js */ \"./src/parser/parser.js\");\n/* harmony import */ var assert__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! assert */ \"assert\");\n/* harmony import */ var assert__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(assert__WEBPACK_IMPORTED_MODULE_2__);\n\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (function() {\n \n // load a couple test files\n // yes one promise can have multiple thens, I checked in chrome console\n let styles_dir = './src/parser/test/styles/';\n let file_ambig = Object(_loader_loader_js__WEBPACK_IMPORTED_MODULE_0__[\"load\"])(styles_dir + 'ambig.play');\n let file_example = Object(_loader_loader_js__WEBPACK_IMPORTED_MODULE_0__[\"load\"])(styles_dir + 'example.play');\n \n /**\n * Parser smoketest: try parsing an old/modified version of the swing style\n * (this is the file I add new features to when I'm modifying the grammar)\n */\n file_example.then(_parser_js__WEBPACK_IMPORTED_MODULE_1__[\"parse\"]).then(ast => {\n ast.init()\n // assert.ok(ast.tracks[0] typeof Track);\n });\n \n /** test for grammar ambiguities with:\n * - \"|\" and \"&\"-separated lists\n * - whitespace-separated lists\n * - multiple lines of // comments\n */\n file_ambig\n .then(_parser_js__WEBPACK_IMPORTED_MODULE_1__[\"string_to_ast\"])\n .then(results => {\n assert__WEBPACK_IMPORTED_MODULE_2___default.a.equal(results.length, 1, 'expected 1 parse (grammar ambiguous)');\n });\n});;\n\n\n//# sourceURL=webpack:///./src/parser/test/test.js?"); - -/***/ }), - -/***/ "./test/song.js": -/*!**********************!*\ - !*** ./test/song.js ***! - \**********************/ -/*! exports provided: Song */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Song\", function() { return Song; });\n/*\n* Everything in this file will move soon, this is just for testing rn\n*/\n\n/**\n * An array-like object that represents a song\n */\nclass Song extends Array {\n constructor(measures) {\n super(...measures);\n this._idx = -1;\n }\n getKey() {\n return this[0][0];\n }\n [Symbol.iterator]() {\n return new SongIterator(this);\n }\n}\n\n/**\n * An extension to the Iterator protocol with some extra bits for our enjoyment\n */\nclass SongIterator {\n constructor(song) {\n this.song = song;\n this.index = -1;\n }\n next() {\n if(++this.index < this.song.length) {\n return {value: this.song[this.index], done: false};\n } else {\n return {value: undefined, done: true};\n }\n }\n get(idx) {\n return this.song[idx];\n }\n getRelative(dist = 0) {\n return this.song[this.index + dist];\n }\n}\n\n//# sourceURL=webpack:///./test/song.js?"); - -/***/ }), - -/***/ "./test/test.js": -/*!**********************!*\ - !*** ./test/test.js ***! - \**********************/ -/*! no exports provided */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _src_parser_test_test_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../src/parser/test/test.js */ \"./src/parser/test/test.js\");\n/* harmony import */ var _song_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./song.js */ \"./test/song.js\");\n/* harmony import */ var _src_index_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../src/index.js */ \"./src/index.js\");\n\n\n\n\n//const verbose = process.argv.includes('--verbose');\n\n// run parser tests\nObject(_src_parser_test_test_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"])();\n\n// @TODO: have a set of tests directly on playback.js to make sure the apis\n// export correctly cuz webpack is being iffy about that\n\n(async function() {\n let song = new _song_js__WEBPACK_IMPORTED_MODULE_1__[\"Song\"]([\n // Each array is a measure, and each item in an array is a beat.\n // null inside a measure means there's no chord set for that beat.\n ['A-', null, null, null], ['E', null, null, null], ['A-7', null, null, null], ['A-6', null, null, null],\n ['CM7', null, 'A7', null], ['D-7', null, 'G7', null], ['C6', null, null, null], ['Bdim7', null, 'E7', null],\n ['A-', null, null, null], ['E', null, null, null], ['A-7', null, null, null], ['A-6', null, null, null],\n ['CM7', null, 'A7', null], ['D-7', null, 'G7', null], ['C6', null, null, null], ['C6', null, null, null]\n ]);\n\n let style = new _src_index_js__WEBPACK_IMPORTED_MODULE_2__[\"PlaybackStyle\"]('./test/styles/example.play');\n await style.init();\n style.play(song);\n})();\n\n//# sourceURL=webpack:///./test/test.js?"); - -/***/ }), - -/***/ "assert": -/*!*************************!*\ - !*** external "assert" ***! - \*************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports = require(\"assert\");\n\n//# sourceURL=webpack:///external_%22assert%22?"); - -/***/ }), - -/***/ "fs": -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports = require(\"fs\");\n\n//# sourceURL=webpack:///external_%22fs%22?"); - -/***/ }), - -/***/ "path": -/*!***********************!*\ - !*** external "path" ***! - \***********************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("module.exports = require(\"path\");\n\n//# sourceURL=webpack:///external_%22path%22?"); - -/***/ }) - -/******/ }); \ No newline at end of file diff --git a/test/test.js b/test/test.js deleted file mode 100644 index 4b0793e..0000000 --- a/test/test.js +++ /dev/null @@ -1,26 +0,0 @@ -import parser_tests from '../src/parser/test/test.js'; -import {Song} from './song.js'; -import {PlaybackStyle} from '../src/index.js'; - -//const verbose = process.argv.includes('--verbose'); - -// run parser tests -parser_tests(); - -// @TODO: have a set of tests directly on playback.js to make sure the apis -// export correctly cuz webpack is being iffy about that - -(async function() { - let song = new Song([ - // Each array is a measure, and each item in an array is a beat. - // null inside a measure means there's no chord set for that beat. - ['A-', null, null, null], ['E', null, null, null], ['A-7', null, null, null], ['A-6', null, null, null], - ['CM7', null, 'A7', null], ['D-7', null, 'G7', null], ['C6', null, null, null], ['Bdim7', null, 'E7', null], - ['A-', null, null, null], ['E', null, null, null], ['A-7', null, null, null], ['A-6', null, null, null], - ['CM7', null, 'A7', null], ['D-7', null, 'G7', null], ['C6', null, null, null], ['C6', null, null, null] - ]); - - let style = new PlaybackStyle('./test/styles/example.play'); - await style.init(); - style.play(song); -})(); \ No newline at end of file diff --git a/test/test.ts b/test/test.ts new file mode 100644 index 0000000..738f149 --- /dev/null +++ b/test/test.ts @@ -0,0 +1,15 @@ +const { Song } = require('notochord-song'); +const blueSkies = require('notochord-song/blueSkies.mjs'); +const {PlaybackStyle} = require('../dist/playback.web.mjs'); + +//const verbose = process.argv.includes('--verbose'); + +// @TODO: have a set of tests directly on playback.js to make sure the apis +// export correctly cuz webpack is being iffy about that + +(async function() { + let song = new Song(blueSkies); + let style = new PlaybackStyle('./test/styles/example.play'); + await style.init(); + style.play(song); +})(); \ No newline at end of file diff --git a/test/tsconfig.json b/test/tsconfig.json new file mode 100644 index 0000000..ea29cc5 --- /dev/null +++ b/test/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "removeComments": false, + "noImplicitAny": false + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e203042 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "es6", + "removeComments": false, + "noImplicitAny": false, + }, + "files": [ + "src/playback.ts", + // "src/interfaces.d.ts" + ], +} \ No newline at end of file diff --git a/types/MIDI/Note.d.ts b/types/MIDI/Note.d.ts new file mode 100644 index 0000000..569c6e3 --- /dev/null +++ b/types/MIDI/Note.d.ts @@ -0,0 +1,32 @@ +/** + * Special pitch value meaning the note will be set later by a DrumBeatGroup + */ +declare let AwaitingDrum: symbol; +export { AwaitingDrum }; +export declare class Note { + time: number; + pitch: string | symbol; + duration: number; + volume: number; + /** + * @param {Object} opts Options object. + * @param {number} opts.time The note's time, in beats. + * @param {string | symbol} opts.pitch A string representing the pitch and octave of the note. e.x. 'A4' + * @param {number} opts.duraion The note's duration, in beats. + * @param {number} opts.volume The note's volume, as a float 0-1 (inclusive). + */ + constructor(opts: any); + /** + * An integer representing the MIDI pitch value of the note. + * @type {number} + */ + readonly midi: any; + /** + * An integer 0-127 that roughly correlates to volume + * @type {number} + */ + readonly velocity: number; +} +export declare class NoteSet extends Array { + constructor(...args: any[]); +} diff --git a/types/PlaybackStyle/PlaybackStyle.d.ts b/types/PlaybackStyle/PlaybackStyle.d.ts new file mode 100644 index 0000000..4910c7c --- /dev/null +++ b/types/PlaybackStyle/PlaybackStyle.d.ts @@ -0,0 +1,32 @@ +export default class PlaybackStyle { + private mainPath; + private ASTs; + private initialized; + private main; + /** + * Set the main ast (the one that plays all its instruments by default). + * @param {ast.GlobalScope} main the main ast + * @param {Map.} asts A map of asts by their path + */ + constructor(mainPath: any); + /** + * Parse each file, pull its dependencies, put it all in a cache, rinse and + * repeat. + * @private + */ + _loadDependencies(): Promise; + _link(): void; + /** + * Initialize the style, which includes loading dependencies and linking + * track/pattern calls. Must be called before compiling/playing. + */ + init(): Promise; + /** + * Compile a song into a set of MIDI-like note instructions. + * @param {Song} song A Playback Song (notochord????) + * @returns {NoteSet.} An array-like object containing MIDI-like note + * instructions. + */ + compile(song: any): Map; + getInstruments(): Set; +} diff --git a/types/Player/Player.d.ts b/types/Player/Player.d.ts new file mode 100644 index 0000000..9222082 --- /dev/null +++ b/types/Player/Player.d.ts @@ -0,0 +1,15 @@ +export default class Player { + private style; + private initialized; + soundfonts: Map; + context: AudioContext; + /** + * Loads the necessary soundfonts and plays a song in a PlaybackStyle in the + * browser. + * @param {AudioContext=} context If you pass it an AudioContext it'll use + * it. Otherwise it'll make its own. + */ + constructor(context: any); + setStyle(style: any): Promise; + play(song: any): void; +} diff --git a/types/ast/ArgumentOperators.d.ts b/types/ast/ArgumentOperators.d.ts new file mode 100644 index 0000000..1b0794a --- /dev/null +++ b/types/ast/ArgumentOperators.d.ts @@ -0,0 +1,28 @@ +import Scope from './Scope'; +import SongIterator from 'notochord-song/types/songiterator'; +declare type Anchor = 'KEY' | 'NEXT' | 'STEP' | 'ARPEGGIATE'; +export declare class AnchorArgument { + anchor: Anchor; + constructor(anchor: Anchor); +} +declare class BooleanOperator { + args: any[]; + scope: Scope; + constructor(...args: any[]); + link(ASTs: any, parentStyle: any, parentTrack: any): void; + init(scope: Scope): void; + resolve_args(songIterator: SongIterator): any[]; +} +export declare class BooleanNot extends BooleanOperator { + constructor(...args: any[]); + execute(songIterator: SongIterator): boolean; +} +export declare class BooleanAnd extends BooleanOperator { + constructor(...args: any[]); + execute(songIterator: SongIterator): boolean; +} +export declare class BooleanOr extends BooleanOperator { + constructor(...args: any[]); + execute(songIterator: SongIterator): boolean; +} +export {}; diff --git a/types/ast/BeatGroups.d.ts b/types/ast/BeatGroups.d.ts new file mode 100644 index 0000000..6c51d80 --- /dev/null +++ b/types/ast/BeatGroups.d.ts @@ -0,0 +1,34 @@ +import { MelodicBeatLiteral } from './BeatLiterals'; +import Scope from './Scope'; +import SongIterator from 'notochord-song/types/songiterator'; +export declare class BeatGroupLiteral { + measures: Measure[]; + scope: Scope; + parentBeatGroup: BeatGroupLiteral; + constructor(measures: Measure[]); + init(scope: any): void; + link(): void; + execute(songIterator: any): any; + getNextStaticBeatRoot(measureIndex: any, beatIndex: any, songIterator: any): any; +} +export declare class Measure { + beats: MelodicBeatLiteral[] | DrumBeatGroupLiteral[]; + beatsPerMeasure: number; + scope: Scope; + parentBeatGroup: BeatGroupLiteral; + indexInBeatGroup: number; + constructor(beats: MelodicBeatLiteral[] | DrumBeatGroupLiteral[]); + calculateDurationAfter(beatIndex: any): number; + getNextStaticBeatRoot(beatIndex: any, songIterator: any): any; + init(scope: any, parentBeatGroup: any, indexInBeatGroup: any): void; + execute(songIterator: SongIterator): any; +} +export declare class DrumBeatGroupLiteral { + beatGroup: BeatGroupLiteral; + scope: Scope; + drum: string; + constructor(drum: any, beatGroup: any); + init(scope: any): void; + link(): void; + execute(songIterator: SongIterator): any; +} diff --git a/types/ast/BeatLiterals.d.ts b/types/ast/BeatLiterals.d.ts new file mode 100644 index 0000000..d8985a2 --- /dev/null +++ b/types/ast/BeatLiterals.d.ts @@ -0,0 +1,61 @@ +import { NoteSet } from '../MIDI/Note'; +import Scope from './Scope'; +import { Measure } from './BeatGroups'; +import SongIterator from 'notochord-song/types/songiterator'; +declare type TimePart = { + time: 'auto' | number; + flag?: 'STACCATO' | 'ACCENTED'; +}; +declare type PitchPart = { + degree: number; + anchor?: 'KEY' | 'NEXT' | 'STEP' | 'ARPEGGIATE'; + roll?: 'ROLL_UP' | 'ROLL_DOWN'; + chord: boolean; +}; +export declare class MelodicBeatLiteral { + time: TimePart; + pitch: PitchPart; + octave: number | 'inherit'; + scope: Scope; + parentMeasure: Measure; + indexInMeasure: number; + cachedAnchor: any; + constructor(opts: any); + init(scope: any, parentMeasure: any, indexInMeasure: any): void; + getTime(): number; + /** + * Normalize a chord into a form tonal can handle + * @param {string} [chord=''] + * @return {string} + */ + static normalizeChord(chord?: string): string; + static chordToScaleName(chord: any): string; + handleInversion(songIterator: any, pitches: any): any[]; + static getAnchorChord(anchor: any, songIterator: SongIterator, currentTime: any): string; + static anchorChordToRoot(anchorChord: any, degree: any, octave: any): any; + getAnchorData(songIterator: any): any[]; + getPitches(songIterator: SongIterator): any; + /** + * Returns true if the beat is anchored via STEP or ARPEGGIATE + * @returns {boolean} + */ + isDynamic(): boolean; + getOctave(): any; + getDuration(): any; + getVolume(): any; + execute(songIterator: any): NoteSet; +} +export declare class DrumBeatLiteral { + time: number; + accented: boolean; + scope: Scope; + parentMeasure: Measure; + indexInMeasure: number; + constructor(opts: any); + init(scope: any, parentMeasure: any, indexInMeasure: any): void; + getTime(): number; + getDuration(): any; + getVolume(): any; + execute(songIterator: any): NoteSet; +} +export {}; diff --git a/types/ast/ConfigStatements.d.ts b/types/ast/ConfigStatements.d.ts new file mode 100644 index 0000000..90f74e5 --- /dev/null +++ b/types/ast/ConfigStatements.d.ts @@ -0,0 +1,18 @@ +import Scope from './Scope'; +import FunctionCall from './FunctionCall'; +import GlobalScope from './GlobalScope'; +export declare class MetaStatement extends Scope { + functionCalls: FunctionCall[]; + constructor(functionCalls: FunctionCall[]); + init(scope: GlobalScope): void; +} +export declare class OptionsStatement extends Scope { + functionCalls: FunctionCall[]; + constructor(functionCalls: any); + init(scope: GlobalScope): void; +} +export declare class ImportStatement { + path: string; + identifier: string; + constructor(path: any, identifier: any); +} diff --git a/types/ast/FunctionCall.d.ts b/types/ast/FunctionCall.d.ts new file mode 100644 index 0000000..b3a2070 --- /dev/null +++ b/types/ast/FunctionCall.d.ts @@ -0,0 +1,29 @@ +import SongIterator from 'notochord-song/types/songiterator'; +import Scope from './Scope'; +declare type FunctionDefinition = { + types: (Function | string)[] | '*'; + scope: 'meta' | 'options' | 'no-config' | 'pattern' | 'no-meta'; + returns: string | Function | symbol; + execute: (args: any[], songIterator: SongIterator, scope: Scope) => any; +}; +/** + * If the value is a FunctionCall, call it and return the returned value. + * Otherwise, return the value itself. + * @private + */ export default class FunctionCall { + identifier: string; + definition: FunctionDefinition; + args: any[]; + scope: Scope; + returns: string | Function | symbol; + /** + * @constructor + * @param {string} identifier The name of the function. Ideally it should + * match the name of one of the functions in function_data.js + */ + constructor(identifier: any, args: any); + init(scope: Scope): void; + link(ASTs: any, parentStyle: any, parentTrack: any): void; + execute(songIterator?: SongIterator): any; +} +export {}; diff --git a/types/ast/GlobalScope.d.ts b/types/ast/GlobalScope.d.ts new file mode 100644 index 0000000..aba4c8b --- /dev/null +++ b/types/ast/GlobalScope.d.ts @@ -0,0 +1,21 @@ +import { NoteSet } from '../MIDI/Note'; +import Scope from './Scope'; +import { MetaStatement, OptionsStatement, ImportStatement } from './ConfigStatements'; +import { TrackStatement, TrackCall } from './Track'; +import SongIterator from 'notochord-song/types/songiterator'; +declare type Statement = MetaStatement | OptionsStatement | ImportStatement | TrackStatement | TrackCall; +export default class GlobalScope extends Scope { + statements: Statement[]; + metaStatements: (MetaStatement | OptionsStatement)[]; + importedStyles: Map; + dependencies: string[]; + tracks: Map; + trackCalls: TrackCall[]; + metadata?: Map; + constructor(statements: any); + init(): void; + link(ASTs: any): void; + execute(songIterator: SongIterator): Map; + getInstruments(): Set; +} +export {}; diff --git a/types/ast/Pattern.d.ts b/types/ast/Pattern.d.ts new file mode 100644 index 0000000..e261c56 --- /dev/null +++ b/types/ast/Pattern.d.ts @@ -0,0 +1,44 @@ +import { NoteSet } from '../MIDI/Note'; +import Scope from './Scope.js'; +import FunctionCall from './FunctionCall.js'; +import SongIterator from 'notochord-song/types/songiterator'; +export declare class PatternExpressionGroup extends Scope { + expressions: any[]; + functionCalls: FunctionCall[]; + nonFunctionCallExpressions: any[]; + patternStatement: PatternStatement; + constructor(expressions: any); + init(scope: any, patternStatement?: any): void; + link(ASTs: any, parentStyle: any, parentTrack: any): void; + execute(songIterator: any, callerIsTrack?: boolean): symbol | NoteSet; +} +export declare class PatternStatement extends PatternExpressionGroup { + identifier: string; + condition?: any; + constructor(opts: any); + getChance(): any; + link(ASTs: any, parentStyle: any, parentTrack: any): void; + init(scope: any): void; + execute(songIterator: SongIterator, callerIsTrack?: boolean): symbol | NoteSet; +} +export declare class PatternCall { + import?: string; + track?: string; + pattern: string; + scope: Scope; + patternStatement: PatternStatement; + prettyprintname: string; + constructor(opts: any); + getChance(): any; + init(scope: any): void; + link(ASTs: any, parentStyle: any, parentTrack: any): void; + execute(songIterator: SongIterator): symbol | NoteSet; +} +export declare class JoinedPatternExpression { + patterns: any[]; + scope: Scope; + constructor(patterns: any); + init(scope: any): void; + link(ASTs: any, parentStyle: any, parentTrack: any): void; + execute(songIterator: SongIterator): symbol | any[]; +} diff --git a/types/ast/Scope.d.ts b/types/ast/Scope.d.ts new file mode 100644 index 0000000..d43a020 --- /dev/null +++ b/types/ast/Scope.d.ts @@ -0,0 +1,10 @@ +export default class Scope { + defaultVars: Map; + vars: Map; + name: string; + type: string; + scope: Scope; + constructor(); + inherit(): void; + init(scope: any): void; +} diff --git a/types/ast/Track.d.ts b/types/ast/Track.d.ts new file mode 100644 index 0000000..65c60a4 --- /dev/null +++ b/types/ast/Track.d.ts @@ -0,0 +1,23 @@ +import Scope from './Scope'; +import FunctionCall from './FunctionCall'; +import { PatternStatement, PatternCall } from './Pattern'; +import SongIterator from 'notochord-song/types/songiterator'; +export declare class TrackStatement extends Scope { + instrument: string; + identifier: string; + members: (FunctionCall | PatternStatement | PatternCall)[]; + functionCalls: FunctionCall[]; + patterns: Map; + patternCalls: PatternCall[]; + constructor(opts: any); + init(scope: any): void; + link(ASTs: any, parentStyle: any): void; + execute(songIterator: any): any; +} +export declare class TrackCall { + import: string; + track: string; + trackStatement: TrackStatement; + constructor(opts: any); + execute(songIterator: SongIterator): void; +} diff --git a/types/ast/ast_nodes.d.ts b/types/ast/ast_nodes.d.ts new file mode 100644 index 0000000..83acdc1 --- /dev/null +++ b/types/ast/ast_nodes.d.ts @@ -0,0 +1,16 @@ +/** + * Constructors for most kinds of nodes in the AST (excuding strings and things + * that can be represented more easily by their JS value). + * + * It's probably bad form/risky to parse directly to the form that's + * interpreted. Eh. + */ +import GlobalScope from './GlobalScope.js'; +import { MetaStatement, OptionsStatement, ImportStatement } from './ConfigStatements.js'; +import { TrackStatement, TrackCall } from './Track.js'; +import { PatternStatement, PatternExpressionGroup, PatternCall, JoinedPatternExpression } from './Pattern.js'; +import FunctionCall from './FunctionCall.js'; +import { AnchorArgument, BooleanNot, BooleanAnd, BooleanOr } from './ArgumentOperators.js'; +import { BeatGroupLiteral, Measure, DrumBeatGroupLiteral } from './BeatGroups.js'; +import { MelodicBeatLiteral, DrumBeatLiteral } from './BeatLiterals.js'; +export { GlobalScope, MetaStatement, OptionsStatement, ImportStatement, TrackStatement, TrackCall, PatternStatement, PatternExpressionGroup, PatternCall, JoinedPatternExpression, FunctionCall, AnchorArgument, BooleanNot, BooleanAnd, BooleanOr, BeatGroupLiteral, Measure, DrumBeatGroupLiteral, MelodicBeatLiteral, DrumBeatLiteral }; diff --git a/types/ast/errors.d.ts b/types/ast/errors.d.ts new file mode 100644 index 0000000..34c49fd --- /dev/null +++ b/types/ast/errors.d.ts @@ -0,0 +1,34 @@ +declare class PlaybackError extends Error { + constructor(message: any, scope: any); +} +export declare class ImportError extends PlaybackError { + constructor(message: any, scope: any); +} +export declare class NoSuchStyleError extends ImportError { + constructor(identifier: any, scope: any); +} +export declare class NoSuchTrackError extends ImportError { + constructor(style: any, track: any, scope: any); +} +export declare class NoSuchPatternError extends ImportError { + constructor(style: any, track: any, pattern: any, scope: any); +} +export declare class FunctionNameError extends PlaybackError { + constructor(identifier: any, scope: any); +} +export declare class FunctionScopeError extends PlaybackError { + constructor(message: any, scope: any); +} +export declare class FunctionArgumentsError extends PlaybackError { + constructor(message: any, scope: any); +} +export declare class TooManyBeatsError extends PlaybackError { + constructor(scope: any); +} +export declare class MelodicBeatInDrumBeatGroupError extends PlaybackError { + constructor(scope: any); +} +export declare class DrumBeatInMelodicBeatGroupError extends PlaybackError { + constructor(scope: any); +} +export {}; diff --git a/types/ast/function_data.d.ts b/types/ast/function_data.d.ts new file mode 100644 index 0000000..0486cec --- /dev/null +++ b/types/ast/function_data.d.ts @@ -0,0 +1,25 @@ +declare let definitions: Map; +/** + * Make an assertion about argument count and types. + * @param {string} identifier The function name. + * @param {Array} args The arguments passed to the function. + * @param {Array.} types Array of the types (typeof) or classes + * (instanceof) to expect. + * @param {Scope} scope The scope, for error logging. + */ +export declare function assertArgTypes(identifier: any, args: any, types: any, scope: any): void; +/** + * Make an assertion about the scope in which the function is called. + * @param {string} identifier The function's name. + * @param {string='no-meta'} goalscope One of 4 string options: + * - 'meta': the function throws if it's called outside a @meta block. + * - 'options': the function throws if it's called outside an @options block. + * - 'no-config': the function throws if it's called inside a @meta or @options + * block, but runs anywhere else that the parser will let you call a function. + * - 'pattern': the function throws if called outside a pattern scope. + * - 'no-meta' (default): the function throws if it's called inside a @meta + * block, but runs anywhere else that the parser will let you call a function. + * @param {Scope} scope The calling scope. + */ +export declare function assertScope(identifier: any, goalscope: string, scope: any): void; +export { definitions }; diff --git a/types/ast/type_utils.d.ts b/types/ast/type_utils.d.ts new file mode 100644 index 0000000..55c395e --- /dev/null +++ b/types/ast/type_utils.d.ts @@ -0,0 +1,3 @@ +declare let Nil: symbol; +declare let cast_bool: (arg: any) => boolean; +export { Nil, cast_bool }; diff --git a/types/loader/loader.d.ts b/types/loader/loader.d.ts new file mode 100644 index 0000000..39c730a --- /dev/null +++ b/types/loader/loader.d.ts @@ -0,0 +1,14 @@ +/** + * Load a file. + * + * * Style locator algorithm: + * 1. If the path begins with http:// or https://, look at that URL + * 2. If the path begins with . or / look in the filesystem or at a relative URL + * 3. Otherwise, look in the styles folder in this repo (which will move to its + * own repo eventually). For these built-in styles, the .play file extension + * is not required. + * + * @param {string} path The path to the file to load. + * @return {string} The content of the file. + */ +export declare function load(stylePath: any): Promise; diff --git a/types/parser/parser.d.ts b/types/parser/parser.d.ts new file mode 100644 index 0000000..25cbe7f --- /dev/null +++ b/types/parser/parser.d.ts @@ -0,0 +1,20 @@ +import { GlobalScope } from '../ast/ast_nodes'; +/** + * Parses a string into a set of possible abstract systax trees (ASTs) trees of + * objects representing the syntax of the file. + * @param {string} data The string to parse + * @return {Promise..} A promise that resolves to an array + * of parsings, each of which is an AST. (Ideally there should be 1 parsing.) + * + * See ast_nodes.js or the grammar itself for an idea of what the nodes in the + * tree might look like. + * @private + */ +export declare function getPossibleParses(data: string): Promise; +/** + * Parse a string into an Abstract Syntax Tree (AST) -- a tree of objects + * representing the syntax of the file. + * @param {string} data The string to parse + * @return {Promise.} The Abstract Systax Tree (AST). + */ +export declare function parse(data: string): Promise; diff --git a/types/playback.d.ts b/types/playback.d.ts new file mode 100644 index 0000000..b0e58a0 --- /dev/null +++ b/types/playback.d.ts @@ -0,0 +1,2 @@ +export { default as PlaybackStyle } from './PlaybackStyle/PlaybackStyle'; +export { default as Player } from './Player/Player'; diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index 1754e2d..0000000 --- a/webpack.config.js +++ /dev/null @@ -1,51 +0,0 @@ -const path = require('path'); -const onBuild = require('on-build-webpack'); -const { exec } = require('child_process'); -const {NormalModuleReplacementPlugin} = require('webpack'); - -module.exports = [ - // package playback - { - entry: './src/index.js', - output: { - filename: 'playback.js' - }, - stats: 'errors-only', - target: 'web', - mode: 'production', - }, - - // bundle and run the test suite - { - entry: './test/test.js', - output: { - path: path.resolve(__dirname, 'test/'), - filename: 'test.bundle.js', - - }, - stats: 'errors-only', - target: 'node', - node: { - __dirname: true, - __filename: true, - }, - mode: 'development', - plugins: [ - new NormalModuleReplacementPlugin( - /loader\.js/, - path.resolve(__dirname, 'src/loader/loader-node.js') - ), - new onBuild(function(stats) { - exec('npm run test', (err, stdout, stderr) => { - if(stdout) console.log(stdout); - if(err || stderr) { - console.error(err || stderr); - console.log(`${new Date()} - failed`); - } else { - console.log(`${new Date()} - ok`); - } - }); - }) - ] - } -]; From 4d16f2a3d077fbd38a69e7a946b83132f08d9535 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Sun, 26 Apr 2020 22:12:08 -0600 Subject: [PATCH 2/6] just... why did I do these things in these ways --- README.md | 7 +- dist/playback.cjs | 12 +-- dist/playback.node.mjs | 12 +-- dist/playback.web.mjs | 12 +-- package-lock.json | 184 +++++++++++++++++++++++++++++++++++++++ package.json | 2 + src/ast/function_data.ts | 38 +++++--- src/ast/type_utils.ts | 3 +- test/playground.html | 27 ++++++ 9 files changed, 261 insertions(+), 36 deletions(-) create mode 100644 test/playground.html diff --git a/README.md b/README.md index bbfb924..6309cae 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,9 @@ So I set off to create my very own language to define a playback style. The end. ## Building and testing, etc. -- `npm test` - run the test suite, print nothing if all tests pass -- `npm run build` - compile the grammar and bundle the files into - `dist/playback.js`. Also bundle the tests and run them -- `npm run build-watch` - rebuild (and rerun tests) every time you change a file +- `npm test` - run the test suite +- `npm run build` - compile and bundle +- `npm run playgrouns` - open the playground ## Credits diff --git a/dist/playback.cjs b/dist/playback.cjs index b504240..fc6cbc1 100644 --- a/dist/playback.cjs +++ b/dist/playback.cjs @@ -1675,7 +1675,7 @@ define$1('time-signature', { returns: Nil }, (args, songIterator, scope, argErr) => { if (!Number.isInteger(Math.log2(args[1]))) { - argErr('Argument 2 of "time-signature" must be a power of 2.'); + argErr(`Argument 2 of "time-signature" must be a power of 2 (got ${args}).`); } scope.vars.set('time-signature', [args[0], args[1]]); return Nil; @@ -1688,7 +1688,7 @@ define$1('volume', { returns: Nil }, (args, songIterator, scope, argErr) => { if (args[0] < 0 || args[0] > 1) { - argErr('Argument 1 of "volume" must be in range 0-1 (inclusive).'); + argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive) (got ${args}).`); } scope.vars.set('volume', args[0]); return Nil; @@ -1700,7 +1700,7 @@ define$1('octave', { returns: Nil }, (args, songIterator, scope, argErr) => { if (!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { - argErr('Argument 1 of "octave" must be an integer 0-9.'); + argErr(`Argument 1 of "octave" must be an integer 0-9 (got ${args}).`); } scope.vars.set('octave', args[0]); return Nil; @@ -1741,7 +1741,7 @@ define$1('progression', { let arg = args[i]; let [, goal] = anchorOrNumberToChordAndRoot(arg, songIterator); if (!goal) { - argErr('Arguments of "progression" must be numbers or anchors.'); + argErr(`Arguments of "progression" must be numbers or anchors (got "${args}").`); } let actualMeasure = songIterator.getRelative(Number(i)); if (!actualMeasure) @@ -1761,7 +1761,7 @@ define$1('in-scale', { let [, note] = anchorOrNumberToChordAndRoot(args[0], songIterator); let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); if (!note || !goalChord) { - argErr('Arguments of "in-scale" must be numbers or anchors.'); + argErr(`Arguments of "in-scale" must be numbers or anchors (got ${args}).`); } let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); let goalScale = tonal$1.Scale.notes(goalTonic, goalScaleName); @@ -1786,7 +1786,7 @@ define$1('chance', { returns: Nil }, (args, songIterator, scope, argErr) => { if (args[0] < 0 || args[0] > 1) { - argErr('Argument 1 of "chance" must be in range 0-1 (inclusive).'); + argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive) (got ${args}).`); } scope.vars.set('chance', args[0]); return Nil; diff --git a/dist/playback.node.mjs b/dist/playback.node.mjs index 1849da6..44083c0 100644 --- a/dist/playback.node.mjs +++ b/dist/playback.node.mjs @@ -1650,7 +1650,7 @@ define$1('time-signature', { returns: Nil }, (args, songIterator, scope, argErr) => { if (!Number.isInteger(Math.log2(args[1]))) { - argErr('Argument 2 of "time-signature" must be a power of 2.'); + argErr(`Argument 2 of "time-signature" must be a power of 2 (got ${args}).`); } scope.vars.set('time-signature', [args[0], args[1]]); return Nil; @@ -1663,7 +1663,7 @@ define$1('volume', { returns: Nil }, (args, songIterator, scope, argErr) => { if (args[0] < 0 || args[0] > 1) { - argErr('Argument 1 of "volume" must be in range 0-1 (inclusive).'); + argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive) (got ${args}).`); } scope.vars.set('volume', args[0]); return Nil; @@ -1675,7 +1675,7 @@ define$1('octave', { returns: Nil }, (args, songIterator, scope, argErr) => { if (!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { - argErr('Argument 1 of "octave" must be an integer 0-9.'); + argErr(`Argument 1 of "octave" must be an integer 0-9 (got ${args}).`); } scope.vars.set('octave', args[0]); return Nil; @@ -1716,7 +1716,7 @@ define$1('progression', { let arg = args[i]; let [, goal] = anchorOrNumberToChordAndRoot(arg, songIterator); if (!goal) { - argErr('Arguments of "progression" must be numbers or anchors.'); + argErr(`Arguments of "progression" must be numbers or anchors (got "${args}").`); } let actualMeasure = songIterator.getRelative(Number(i)); if (!actualMeasure) @@ -1736,7 +1736,7 @@ define$1('in-scale', { let [, note] = anchorOrNumberToChordAndRoot(args[0], songIterator); let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); if (!note || !goalChord) { - argErr('Arguments of "in-scale" must be numbers or anchors.'); + argErr(`Arguments of "in-scale" must be numbers or anchors (got ${args}).`); } let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); let goalScale = tonal$1.Scale.notes(goalTonic, goalScaleName); @@ -1761,7 +1761,7 @@ define$1('chance', { returns: Nil }, (args, songIterator, scope, argErr) => { if (args[0] < 0 || args[0] > 1) { - argErr('Argument 1 of "chance" must be in range 0-1 (inclusive).'); + argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive) (got ${args}).`); } scope.vars.set('chance', args[0]); return Nil; diff --git a/dist/playback.web.mjs b/dist/playback.web.mjs index 09baa8c..f0b3336 100644 --- a/dist/playback.web.mjs +++ b/dist/playback.web.mjs @@ -1650,7 +1650,7 @@ define$1('time-signature', { returns: Nil }, (args, songIterator, scope, argErr) => { if (!Number.isInteger(Math.log2(args[1]))) { - argErr('Argument 2 of "time-signature" must be a power of 2.'); + argErr(`Argument 2 of "time-signature" must be a power of 2 (got ${args}).`); } scope.vars.set('time-signature', [args[0], args[1]]); return Nil; @@ -1663,7 +1663,7 @@ define$1('volume', { returns: Nil }, (args, songIterator, scope, argErr) => { if (args[0] < 0 || args[0] > 1) { - argErr('Argument 1 of "volume" must be in range 0-1 (inclusive).'); + argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive) (got ${args}).`); } scope.vars.set('volume', args[0]); return Nil; @@ -1675,7 +1675,7 @@ define$1('octave', { returns: Nil }, (args, songIterator, scope, argErr) => { if (!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { - argErr('Argument 1 of "octave" must be an integer 0-9.'); + argErr(`Argument 1 of "octave" must be an integer 0-9 (got ${args}).`); } scope.vars.set('octave', args[0]); return Nil; @@ -1716,7 +1716,7 @@ define$1('progression', { let arg = args[i]; let [, goal] = anchorOrNumberToChordAndRoot(arg, songIterator); if (!goal) { - argErr('Arguments of "progression" must be numbers or anchors.'); + argErr(`Arguments of "progression" must be numbers or anchors (got "${args}").`); } let actualMeasure = songIterator.getRelative(Number(i)); if (!actualMeasure) @@ -1736,7 +1736,7 @@ define$1('in-scale', { let [, note] = anchorOrNumberToChordAndRoot(args[0], songIterator); let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); if (!note || !goalChord) { - argErr('Arguments of "in-scale" must be numbers or anchors.'); + argErr(`Arguments of "in-scale" must be numbers or anchors (got ${args}).`); } let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); let goalScale = tonal$1.Scale.notes(goalTonic, goalScaleName); @@ -1761,7 +1761,7 @@ define$1('chance', { returns: Nil }, (args, songIterator, scope, argErr) => { if (args[0] < 0 || args[0] > 1) { - argErr('Argument 1 of "chance" must be in range 0-1 (inclusive).'); + argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive) (got ${args}).`); } scope.vars.set('chance', args[0]); return Nil; diff --git a/package-lock.json b/package-lock.json index 372ec7b..b988d96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -120,6 +120,15 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, "babylon": { "version": "7.0.0-beta.19", "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", @@ -132,6 +141,12 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true + }, "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", @@ -232,6 +247,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -244,6 +265,12 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -257,6 +284,15 @@ "which": "^1.2.9" } }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -287,6 +323,26 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, + "ecstatic": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", + "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "dev": true, + "requires": { + "he": "^1.1.1", + "mime": "^1.6.0", + "minimist": "^1.1.0", + "url-join": "^2.0.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } + } + }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", @@ -351,6 +407,12 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "dev": true + }, "flat": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", @@ -368,6 +430,15 @@ } } }, + "follow-redirects": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", + "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", + "dev": true, + "requires": { + "debug": "^3.0.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -431,6 +502,35 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "http-proxy": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-server": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.1.tgz", + "integrity": "sha512-T0jB+7J7GJ2Vo+a4/T7P7SbQ3x2GPDnqRqQXdfEuPuUOmES/9NBxPnDm7dh1HGEeUWqUmLUNtGV63ZC5Uy3tGA==", + "dev": true, + "requires": { + "basic-auth": "^1.0.3", + "colors": "^1.3.3", + "corser": "^2.0.1", + "ecstatic": "^3.3.2", + "http-proxy": "^1.17.0", + "opener": "^1.5.1", + "optimist": "~0.6.1", + "portfinder": "^1.0.20", + "secure-compare": "3.0.1", + "union": "~0.5.0" + } + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -603,6 +703,12 @@ "graceful-fs": "^4.1.9" } }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", @@ -667,6 +773,12 @@ "readable-stream": "^2.0.1" } }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -961,6 +1073,12 @@ } } }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "nice-try": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", @@ -1044,6 +1162,22 @@ "wrappy": "1" } }, + "opener": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", + "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==", + "dev": true + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -1080,12 +1214,29 @@ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, + "portfinder": { + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", + "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" + } + }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, + "qs": { + "version": "6.9.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", + "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", + "dev": true + }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", @@ -1113,6 +1264,12 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, "requizzle": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", @@ -1274,6 +1431,12 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", @@ -1646,6 +1809,21 @@ } } }, + "union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "requires": { + "qs": "^6.4.0" + } + }, + "url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1676,6 +1854,12 @@ "string-width": "^1.0.2 || 2" } }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", diff --git a/package.json b/package.json index 3639be4..474c1bc 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "type": "module", "types": "types/playback.d.ts", "scripts": { + "playground": "npx http-server -o test/playground.html", "test": "TS_NODE_IGNORE=\"/node_modules|(ts$)/\" npx ts-mocha -p test/tsconfig.json test/*.ts", "build-grammar": "npx nearleyc src/parser/grammar.ne -o src/parser/grammar.js", "build": "npx rollup -c; # npm run build-declarations", @@ -25,6 +26,7 @@ "@types/chai": "^4.2.0", "@types/mocha": "^5.2.7", "chai": "^4.2.0", + "http-server": "^0.12.1", "jsdoc": "^3.5.5", "mocha": "^6.1.4", "nearley": "2.13.0", diff --git a/src/ast/function_data.ts b/src/ast/function_data.ts index 6e7e1ff..6a3051c 100644 --- a/src/ast/function_data.ts +++ b/src/ast/function_data.ts @@ -8,6 +8,8 @@ import Scope from './Scope'; let definitions = new Map(); +type ArgType = '*' | 'string' | 'number' | 'boolean' | ((...args: any[]) => void) | Nil; + /** * Make an assertion about argument count and types. * @param {string} identifier The function name. @@ -16,7 +18,7 @@ let definitions = new Map(); * (instanceof) to expect. * @param {Scope} scope The scope, for error logging. */ -export function assertArgTypes(identifier, args, types, scope) { +export function assertArgTypes(identifier: string, args, types: ArgType[] | '*', scope: Scope) { if(types == '*') return; if(args.length != types.length) { throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, scope); @@ -50,6 +52,9 @@ export function assertArgTypes(identifier, args, types, scope) { } } } + +type GoalScope = 'meta' | 'options' | 'no-config' | 'pattern' | 'no-meta'; + /** * Make an assertion about the scope in which the function is called. * @param {string} identifier The function's name. @@ -63,7 +68,7 @@ export function assertArgTypes(identifier, args, types, scope) { * block, but runs anywhere else that the parser will let you call a function. * @param {Scope} scope The calling scope. */ -export function assertScope(identifier, goalscope = 'no-meta', scope) { +export function assertScope(identifier: string, goalscope: GoalScope = 'no-meta', scope: Scope) { if(goalscope == 'meta') { if(scope.type != '@meta') { throw new FunctionScopeError(`Function "${identifier}" must only be called within a @meta block."`, scope); @@ -88,6 +93,13 @@ export function assertScope(identifier, goalscope = 'no-meta', scope) { } } } + +interface IDefineOpts { + types?: ArgType | ArgType[]; + scope?: GoalScope; + returns: ArgType; +} + /** * Define a function. * @param {string} identifier The name of the function. @@ -107,7 +119,7 @@ export function assertScope(identifier, goalscope = 'no-meta', scope) { * - argErr: a function. If the function does further testing on its * arguments and there's an issue, pass this the error message and it throws. */ -let define = function(identifier, opts, func) { +let define = function(identifier: string, opts: IDefineOpts, func: (args: any[], songIterator: SongIterator, scope: Scope, argErr: (message: string) => void) => any) { let definition = { types: opts.types || '*', returns: opts.returns || '*', @@ -133,7 +145,7 @@ let define = function(identifier, opts, func) { * See assertScope above. */ let defineVar = function(identifier, type, goalscope = null) { - let opts = { + let opts: IDefineOpts = { types: [type], scope: goalscope, returns: Nil @@ -152,10 +164,10 @@ let defineVar = function(identifier, type, goalscope = null) { * @param {?string=null} goalscope Throw error unless the calling scope matches. * See assertScope above. */ -let defineBoolean = function(identifier, goalscope = null) { - let opts = { +let defineBoolean = function(identifier: string, goalscope = null) { + let opts: IDefineOpts = { types: '*', - scopes: goalscope, + scope: goalscope, returns: Nil } define(identifier, opts, (args, songIterator, scope, argErr) => { @@ -186,7 +198,7 @@ define('time-signature', }, (args, songIterator, scope, argErr) => { if(!Number.isInteger(Math.log2(args[1]))) { - argErr('Argument 2 of "time-signature" must be a power of 2.'); + argErr(`Argument 2 of "time-signature" must be a power of 2 (got ${args}).`); } scope.vars.set('time-signature', [args[0], args[1]]); return Nil; @@ -202,7 +214,7 @@ define('volume', }, (args, songIterator, scope, argErr) => { if(args[0] < 0 || args[0] > 1) { - argErr('Argument 1 of "volume" must be in range 0-1 (inclusive).'); + argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive) (got ${args}).`); } scope.vars.set('volume', args[0]); return Nil; @@ -216,7 +228,7 @@ define('octave', }, (args, songIterator, scope, argErr) => { if(!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { - argErr('Argument 1 of "octave" must be an integer 0-9.'); + argErr(`Argument 1 of "octave" must be an integer 0-9 (got ${args}).`); } scope.vars.set('octave', args[0]); return Nil; @@ -264,7 +276,7 @@ define('progression', let arg = args[i]; let [,goal] = anchorOrNumberToChordAndRoot(arg, songIterator); if(!goal) { - argErr('Arguments of "progression" must be numbers or anchors.'); + argErr(`Arguments of "progression" must be numbers or anchors (got ${args}).`); } let actualMeasure = songIterator.getRelative(Number(i)); if(!actualMeasure) return false; @@ -285,7 +297,7 @@ define('in-scale', let [,note] = anchorOrNumberToChordAndRoot(args[0], songIterator); let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); if(!note || !goalChord) { - argErr('Arguments of "in-scale" must be numbers or anchors.'); + argErr(`Arguments of "in-scale" must be numbers or anchors (got ${args}).`); } let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); let goalScale = tonal.Scale.notes(goalTonic, goalScaleName); @@ -314,7 +326,7 @@ define('chance', }, (args, songIterator, scope, argErr) => { if(args[0] < 0 || args[0] > 1) { - argErr('Argument 1 of "chance" must be in range 0-1 (inclusive).'); + argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive) (got ${args}).`); } scope.vars.set('chance', args[0]); return Nil; diff --git a/src/ast/type_utils.ts b/src/ast/type_utils.ts index 7a2e7d8..9ea6800 100644 --- a/src/ast/type_utils.ts +++ b/src/ast/type_utils.ts @@ -1,4 +1,5 @@ -let Nil = Symbol('Nil'); +const Nil: unique symbol = Symbol('Nil'); +type Nil = typeof Nil; let cast_bool = function(arg) { if(arg === Nil || arg === false) { return false; diff --git a/test/playground.html b/test/playground.html new file mode 100644 index 0000000..61e7cee --- /dev/null +++ b/test/playground.html @@ -0,0 +1,27 @@ + + + Playback Browser Test + + + + + + \ No newline at end of file From 69538ebbc390380021e6e069fba7ca7f2bd9dda7 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Tue, 28 Apr 2020 18:36:47 -0600 Subject: [PATCH 3/6] Box the value types because all the function argument logic was hackily dependent on JS types; more ts port stuff, get it to finish executing the song (albeit very poorly) --- dist/playback.cjs | 732 +++++++++++++++++++---------------- dist/playback.node.mjs | 732 +++++++++++++++++++---------------- dist/playback.web.mjs | 732 +++++++++++++++++++---------------- src/ast/ArgumentOperators.ts | 19 +- src/ast/BeatGroups.ts | 10 +- src/ast/BeatLiterals.ts | 151 ++------ src/ast/FunctionCall.ts | 12 +- src/ast/GlobalScope.ts | 8 +- src/ast/Pattern.ts | 26 +- src/ast/Scope.ts | 6 +- src/ast/Track.ts | 14 +- src/ast/ast_nodes.ts | 4 +- src/ast/errors.ts | 6 +- src/ast/function_data.ts | 162 ++++---- src/ast/music_utils.ts | 79 ++++ src/ast/type_utils.ts | 11 - src/parser/grammar.js | 13 +- src/parser/grammar.ne | 13 +- src/values/beatValues.ts | 76 ++++ src/values/values.ts | 64 +++ 20 files changed, 1600 insertions(+), 1270 deletions(-) create mode 100644 src/ast/music_utils.ts delete mode 100644 src/ast/type_utils.ts create mode 100644 src/values/beatValues.ts create mode 100644 src/values/values.ts diff --git a/dist/playback.cjs b/dist/playback.cjs index fc6cbc1..291d540 100644 --- a/dist/playback.cjs +++ b/dist/playback.cjs @@ -995,16 +995,6 @@ var lexer = moo.states({ } }); -let Nil = Symbol('Nil'); -let cast_bool = function (arg) { - if (arg === Nil || arg === false) { - return false; - } - else { - return true; - } -}; - // does this have to be an Error? idc class PlaybackError extends Error { constructor(message, scope) { @@ -1044,8 +1034,8 @@ class FunctionScopeError extends PlaybackError { } } class FunctionArgumentsError extends PlaybackError { - constructor(message, scope) { - super(message, scope); + constructor(message, args, scope) { + super(`${message} (got ${args.map(a => a.toOutputString()).join(', ')})`, scope); } } /* Pattern-related errors */ @@ -1267,230 +1257,184 @@ class NoteSet extends Array { let tonal$1 = {}; (function(n){function t(n){"string"!=typeof n&&(n="");var t=T.exec(n);return t?[t[1].toUpperCase(),t[2].replace(/x/g,"##"),t[3],t[4]]:null}function r(n,t){return n=Math.round(n),(!0===t?G:I)[n%12]+(Math.floor(n/12)-1)}function e(n,t){for(var r=[];t--;r[t]=t+n);return r}function m(n,t){for(var r=[];t--;r[t]=n-t);return r}function i(n,t){return null===n||null===t?[]:nan(t)})}function P(n){return o(n).filter(function(n,t,r){return 0===t||n!==r[t-1]})}function M(n){return "string"!=typeof n?An:_n[n]||(_n[n]=xn(n))}function a(n){var t=(n+1)%7;return t<0?7+t:t}function l(n,t){if(1===arguments.length)return function(t){return l(n,t)};var r=Kn(n),e=Qn(t);if(null===r||null===e)return null;var m=1===r.length?[r[0]+e[0]]:[r[0]+e[0],r[1]+e[1]];return mn(Un(m[0],m[1]))}function c(n,t){if(1===arguments.length)return function(t){return c(n,t)};var r=Kn(n);return null===r?null:mn(Un(r[0]+t))}function s(n,t){if(1===arguments.length)return function(t){return s(n,t)};var r=Kn(n),e=Kn(t);return null===e||null===r?null:e[0]-r[0]}function f(n,t){return 1===arguments.length?function(t){return l(t,n)}:l(t,n)}function d(n,t,r){var e=Qn(n),m=Qn(t);if(null===e||null===m)return null;var i=[e[0]+r*m[0],e[1]+r*m[1]];return Dn(Wn(i))}function p(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,1)}function b(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,-1)}function h(n,t){if(1===arguments.length)return function(t){return h(n,t)};var r=Kn(n),e=Kn(t);if(null===r||null===e||r.length!==e.length)return null;var m=1===r.length?[e[0]-r[0],-Math.floor(7*(e[0]-r[0])/12)]:[e[0]-r[0],e[1]-r[1]];return Dn(Wn(m))}function v(n,t){if(1===arguments.length)return function(t){return v(n,t)};var r=L(n),e=L(t);return null!==r.midi&&null!==e.midi?e.midi-r.midi:null!==r.chroma&&null!==e.chroma?(e.chroma-r.chroma+12)%12:null}function A(n){if(y(n))return n;if(!Array.isArray(n))return "";var t=[0,0,0,0,0,0,0,0,0,0,0,0];return n.map(nt).forEach(function(n){t[n]=1;}),t.join("")}function g(n){return et=et||i(2048,4095).map(function(n){return n.toString(2)}),"number"==typeof n?et.filter(function(t){return rt(t)===n}):et.slice()}function j(n,t){t=!1!==t;var r=A(n).split("");return Mn(r.map(function(n,e){var m=u(e,r);return t&&"0"===m[0]?null:m.join("")}))}function y(n){return mt.test(n)}function O(n){return y(n)?Mn(n.split("").map(function(n,t){return "1"===n?it[t]:null})):[]}function x(n,t){return 1===arguments.length?function(t){return x(n,t)}:A(n)===A(t)}function _(n,t){return arguments.length>1?_(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t&n)===t})}function z(n,t){return arguments.length>1?z(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t|n)===t})}function q(n,t){return arguments.length>1?q(n)(t):(n=A(n),function(t){return "1"===n[nt(t)]})}function k(n,t){return 1===arguments.length?function(t){return k(n,t)}:t.filter(q(n))}function S(n,t){var r=D(n);return t=t||r[1],pt(t).map(l(r[0]))}function w(n){var t=D(n);return void 0!==Mt(t[1])}function D(n){if("string"!=typeof n)return ["",""];var t=n.indexOf(" "),r=R(n.substring(0,t))||R(n)||"",e=""!==r?n.substring(r.length+1):n;return [r,e.length?e:""]}function E(n,t){var r=C(n);return t=t||r[1],xt(t).intervals.map(l(r[0]))}function C(n){var r=t(n);return ""===r[0]?["",n]:"A"===r[0]&&"ug"===r[3]?["","aug"]:St.test(r[2])?[r[0]+r[1],r[2]+r[3]]:[r[0]+r[1]+r[2],r[3]]}var $="C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B".split(" "),F=function(n){return "string"!=typeof n?$.slice():$.filter(function(t){var r=t[1]||" ";return -1!==n.indexOf(r)})},G=F(" #"),I=F(" b"),T=/^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)$/,B=Object.freeze({pc:null,name:null,step:null,alt:null,oct:null,octStr:null,chroma:null,midi:null,freq:null}),N=[0,2,4,5,7,9,11],L=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var r=t(n);if(""===r[0]||""!==r[3])return B;var e=r[0],m=r[1],i=r[2],u={letter:e,acc:m,octStr:i};return u.pc=u.letter+u.acc,u.name=u.pc+i,u.step=(u.letter.charCodeAt(0)+3)%7,u.alt="b"===u.acc[0]?-u.acc.length:u.acc.length,u.oct=i.length?+i:null,u.chroma=(N[u.step]+u.alt+120)%12,u.midi=null!==u.oct?N[u.step]+u.alt+12*(u.oct+1):null,u.freq=J(u.midi),Object.freeze(u)}),R=function(n){return L(n).name},U=function(n){return L(n).pc},H=function(n){return L(n).midi||+n||null},J=function(n,t){return void 0===t&&(t=440),"number"==typeof n?Math.pow(2,(n-69)/12)*t:null},K=function(n){return L(n).freq||J(n)},Q=Math.log(2),V=Math.log(440),W=function(n){var t=12*(Math.log(n)-V)/Q+69;return Math.round(100*t)/100},X=function(n){return L(n).chroma},Y=function(n){return L(n).oct},Z=function(n){return "CDEFGAB"[n]},nn=function(n,t){return Array(t+1).join(n)},tn=function(n,t){return "number"!=typeof n?"":t(n)},rn=function(n){return tn(n,function(n){return n<0?nn("b",-n):nn("#",n)})},en=function(n,t){void 0===n&&(n={}),void 0===t&&(t=null);var r=t?Object.assign({},L(t),n):n,e=r.step,m=r.alt,i=r.oct,u=Z(e);if(!u)return null;var o=u+rn(m);return i||0===i?o+i:o},mn=en,un=function(n,t){var e=L(n),m=e.alt,i=e.chroma,u=e.midi;if(null===i)return null;var o=!1===t?m<0:m>0;return null===u?U(r(i,o)):r(u,o)},on=function(n){return un(n,!1)},Pn=Object.freeze({names:F,tokenize:t,props:L,name:R,pc:U,midi:H,midiToFreq:J,freq:K,freqToMidi:W,chroma:X,oct:Y,stepToLetter:Z,altToAcc:rn,from:en,build:mn,fromMidi:r,simplify:un,enharmonic:on}),Mn=function(n){return n.filter(function(n){return 0===n||n})},an=function(n){var t=H(n);return null!==t?t:H(n+"-100")},ln=function(n,t){void 0===t&&(t=Math.random);for(var r,e,m=n.length;m;)r=t()*m--|0,e=n[m],n[m]=n[r],n[r]=e;return n},cn=function(n){return 0===n.length?[[]]:cn(n.slice(1)).reduce(function(t,r){return t.concat(n.map(function(t,e){var m=r.slice();return m.splice(e,0,n[0]),m}))},[])},sn=Object.freeze({range:i,rotate:u,compact:Mn,sort:o,unique:P,shuffle:ln,permutations:cn}),fn=new RegExp("^([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})|(AA|A|P|M|m|d|dd)([-+]?\\d+)$"),dn=[0,2,4,5,7,9,11],pn=[0,1,2,3,4,5,6,5,4,3,2,1],bn="1P 2m 2M 3m 3M 4P 5P 6m 6M 7m 7M 8P".split(" "),hn=function(n){return "string"!=typeof n?bn.slice():bn.filter(function(t){return -1!==n.indexOf(t[1])})},vn=function(n){var t=fn.exec(n);return null===t?null:t[1]?[t[1],t[2]]:[t[4],t[3]]},An=Object.freeze({name:null,num:null,q:null,step:null,alt:null,dir:null,type:null,simple:null,semitones:null,chroma:null}),gn=function(n,t){return Array(Math.abs(t)+1).join(n)},jn=function(n,t){return "M"===t&&"M"===n?0:"P"===t&&"P"===n?0:"m"===t&&"M"===n?-1:/^A+$/.test(t)?t.length:/^d+$/.test(t)?"P"===n?-t.length:-t.length-1:null},yn=function(n,t){return 0===t?"M"===n?"M":"P":-1===t&&"M"===n?"m":t>0?gn("A",t):t<0?gn("d","P"===n?t:t+1):null},On=function(n){return (Math.abs(n)-1)%7},xn=function(n){var t=vn(n);if(null===t)return An;var r={num:+t[0],q:t[1]};return r.step=On(r.num),r.type="PMMPPMM"[r.step],"M"===r.type&&"P"===r.q?An:(r.name=""+r.num+r.q,r.dir=r.num<0?-1:1,r.simple=8===r.num||-8===r.num?r.num:r.dir*(r.step+1),r.alt=jn(r.type,r.q),r.oct=Math.floor((Math.abs(r.num)-1)/7),r.semitones=r.dir*(dn[r.step]+r.alt+12*r.oct),r.chroma=(r.dir*(dn[r.step]+r.alt)%12+12)%12,Object.freeze(r))},_n={},zn=function(n){return M(n).num},qn=function(n){return M(n).name},kn=function(n){return M(n).semitones},Sn=function(n){return M(n).chroma},wn=function(n){return "string"==typeof n&&(n=M(n).chroma),"number"==typeof n?pn[n%12]:null},Dn=function(n){void 0===n&&(n={});var t=n.num,r=n.step,e=n.alt,m=n.oct;void 0===m&&(m=1);var i=n.dir;if(void 0!==r&&(t=r+1+7*m),void 0===t)return null;var u=i<0?"-":"",o="PMMPPMM"[On(t)];return u+t+yn(o,e)},En=function(n){var t=M(n);return t===An?null:t.simple+t.q},Cn=function(n){var t=M(n);if(t===An)return null;var r=(7-t.step)%7,e="P"===t.type?-t.alt:-(t.alt+1);return Dn({step:r,alt:e,oct:t.oct,dir:t.dir})},$n=[1,2,2,3,3,4,5,5,6,6,7,7],Fn="P m M m M P d P m M m M".split(" "),Gn=function(n){var t=n<0?-1:1,r=Math.abs(n),e=r%12,m=Math.floor(r/12);return t*($n[e]+7*m)+Fn[e]},In=Object.freeze({names:hn,tokenize:vn,props:M,num:zn,name:qn,semitones:kn,chroma:Sn,ic:wn,build:Dn,simplify:En,invert:Cn,fromSemitones:Gn}),Tn=[0,2,4,-1,1,3,5],Bn=function(n){return Math.floor(7*n/12)},Nn=Tn.map(Bn),Ln=function(n){var t=n.step,r=n.alt,e=n.oct,m=n.dir;void 0===m&&(m=1);var i=Tn[t]+7*r;return null===e?[m*i]:[m*i,m*(e-Nn[t]-4*r)]},Rn=[3,0,4,1,5,2,6],Un=function(n,t,r){var e=Rn[a(n)],m=Math.floor((n+1)/7);return void 0===t?{step:e,alt:m,dir:r}:{step:e,alt:m,oct:t+4*m+Nn[e],dir:r}},Hn=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}},Jn=function(n){return Hn(function(t){var r=n(t);return null===r.name?null:Ln(r)})},Kn=Jn(L),Qn=Jn(M),Vn=function(n){return 7*n[0]+12*n[1]<0},Wn=function(n){return Vn(n)?Un(-n[0],-n[1],-1):Un(n[0],n[1],1)},Xn=Object.freeze({transpose:l,trFifths:c,fifths:s,transposeBy:f,addIntervals:d,add:p,subtract:b,interval:h,semitones:v}),Yn={chromatic:["1P 2m 2M 3m 3M 4P 4A 5P 6m 6M 7m 7M"],lydian:["1P 2M 3M 4A 5P 6M 7M"],major:["1P 2M 3M 4P 5P 6M 7M",["ionian"]],mixolydian:["1P 2M 3M 4P 5P 6M 7m",["dominant"]],dorian:["1P 2M 3m 4P 5P 6M 7m"],aeolian:["1P 2M 3m 4P 5P 6m 7m",["minor"]],phrygian:["1P 2m 3m 4P 5P 6m 7m"],locrian:["1P 2m 3m 4P 5d 6m 7m"],altered:["1P 2m 3m 3M 5d 6m 7m",["super locrian","diminished whole tone","pomeroy"]],iwato:["1P 2m 4P 5d 7m"],hirajoshi:["1P 2M 3m 5P 6m"],kumoijoshi:["1P 2m 4P 5P 6m"],pelog:["1P 2m 3m 5P 6m"],prometheus:["1P 2M 3M 4A 6M 7m"],ritusen:["1P 2M 4P 5P 6M"],scriabin:["1P 2m 3M 5P 6M"],piongio:["1P 2M 4P 5P 6M 7m"],augmented:["1P 2A 3M 5P 5A 7M"],neopolitan:["1P 2m 3m 4P 5P 6m 7M"],diminished:["1P 2M 3m 4P 5d 6m 6M 7M"],egyptian:["1P 2M 4P 5P 7m"],oriental:["1P 2m 3M 4P 5d 6M 7m"],spanish:["1P 2m 3M 4P 5P 6m 7m",["phrygian major"]],flamenco:["1P 2m 3m 3M 4A 5P 7m"],balinese:["1P 2m 3m 4P 5P 6m 7M"],persian:["1P 2m 3M 4P 5d 6m 7M"],bebop:["1P 2M 3M 4P 5P 6M 7m 7M"],enigmatic:["1P 2m 3M 5d 6m 7m 7M"],ichikosucho:["1P 2M 3M 4P 5d 5P 6M 7M"],"melodic minor":["1P 2M 3m 4P 5P 6M 7M"],"melodic minor second mode":["1P 2m 3m 4P 5P 6M 7m"],"lydian augmented":["1P 2M 3M 4A 5A 6M 7M"],"lydian dominant":["1P 2M 3M 4A 5P 6M 7m",["lydian b7"]],"melodic minor fifth mode":["1P 2M 3M 4P 5P 6m 7m",["hindu","mixolydian b6M"]],"locrian #2":["1P 2M 3m 4P 5d 6m 7m"],"locrian major":["1P 2M 3M 4P 5d 6m 7m",["arabian"]],"major pentatonic":["1P 2M 3M 5P 6M",["pentatonic"]],"lydian pentatonic":["1P 3M 4A 5P 7M",["chinese"]],"mixolydian pentatonic":["1P 3M 4P 5P 7m",["indian"]],"locrian pentatonic":["1P 3m 4P 5d 7m",["minor seven flat five pentatonic"]],"minor pentatonic":["1P 3m 4P 5P 7m"],"minor six pentatonic":["1P 3m 4P 5P 6M"],"minor hexatonic":["1P 2M 3m 4P 5P 7M"],"flat three pentatonic":["1P 2M 3m 5P 6M",["kumoi"]],"flat six pentatonic":["1P 2M 3M 5P 6m"],"major flat two pentatonic":["1P 2m 3M 5P 6M"],"whole tone pentatonic":["1P 3M 5d 6m 7m"],"ionian pentatonic":["1P 3M 4P 5P 7M"],"lydian #5P pentatonic":["1P 3M 4A 5A 7M"],"lydian dominant pentatonic":["1P 3M 4A 5P 7m"],"minor #7M pentatonic":["1P 3m 4P 5P 7M"],"super locrian pentatonic":["1P 3m 4d 5d 7m"],"in-sen":["1P 2m 4P 5P 7m"],"vietnamese 1":["1P 3m 4P 5P 6m"],"vietnamese 2":["1P 3m 4P 5P 7m"],"prometheus neopolitan":["1P 2m 3M 4A 6M 7m"],"major blues":["1P 2M 3m 3M 5P 6M"],"minor blues":["1P 3m 4P 5d 5P 7m",["blues"]],"composite blues":["1P 2M 3m 3M 4P 5d 5P 6M 7m"],"augmented heptatonic":["1P 2A 3M 4P 5P 5A 7M"],"dorian #4":["1P 2M 3m 4A 5P 6M 7m"],"lydian diminished":["1P 2M 3m 4A 5P 6M 7M"],"whole tone":["1P 2M 3M 4A 5A 7m"],"leading whole tone":["1P 2M 3M 4A 5A 7m 7M"],"harmonic minor":["1P 2M 3m 4P 5P 6m 7M"],"lydian minor":["1P 2M 3M 4A 5P 6m 7m"],"neopolitan minor":["1P 2m 3m 4P 5P 6m 7M"],"neopolitan major":["1P 2m 3m 4P 5P 6M 7M",["dorian b2"]],"neopolitan major pentatonic":["1P 3M 4P 5d 7m"],"romanian minor":["1P 2M 3m 5d 5P 6M 7m"],"double harmonic lydian":["1P 2m 3M 4A 5P 6m 7M"],"harmonic major":["1P 2M 3M 4P 5P 6m 7M"],"double harmonic major":["1P 2m 3M 4P 5P 6m 7M",["gypsy"]],"hungarian minor":["1P 2M 3m 4A 5P 6m 7M"],"hungarian major":["1P 2A 3M 4A 5P 6M 7m"],"spanish heptatonic":["1P 2m 3m 3M 4P 5P 6m 7m"],"todi raga":["1P 2m 3m 4A 5P 6m 7M"],"malkos raga":["1P 3m 4P 6m 7m"],"kafi raga":["1P 3m 3M 4P 5P 6M 7m 7M"],"purvi raga":["1P 2m 3M 4P 4A 5P 6m 7M"],"bebop dominant":["1P 2M 3M 4P 5P 6M 7m 7M"],"bebop minor":["1P 2M 3m 3M 4P 5P 6M 7m"],"bebop major":["1P 2M 3M 4P 5P 5A 6M 7M"],"bebop locrian":["1P 2m 3m 4P 5d 5P 6m 7m"],"minor bebop":["1P 2M 3m 4P 5P 6m 7m 7M"],"mystery #1":["1P 2m 3M 5d 6m 7m"],"minor six diminished":["1P 2M 3m 4P 5P 6m 6M 7M"],"ionian augmented":["1P 2M 3M 4P 5A 6M 7M"],"lydian #9":["1P 2m 3M 4A 5P 6M 7M"],"six tone symmetric":["1P 2m 3M 4P 5A 6M"]},Zn={M:["1P 3M 5P",["Major",""]],M13:["1P 3M 5P 7M 9M 13M",["maj13","Maj13"]],M6:["1P 3M 5P 13M",["6"]],M69:["1P 3M 5P 6M 9M",["69"]],M7add13:["1P 3M 5P 6M 7M 9M"],M7b5:["1P 3M 5d 7M"],M7b6:["1P 3M 6m 7M"],M7b9:["1P 3M 5P 7M 9m"],M7sus4:["1P 4P 5P 7M"],M9:["1P 3M 5P 7M 9M",["maj9","Maj9"]],M9b5:["1P 3M 5d 7M 9M"],M9sus4:["1P 4P 5P 7M 9M"],Madd9:["1P 3M 5P 9M",["2","add9","add2"]],Maj7:["1P 3M 5P 7M",["maj7","M7"]],Mb5:["1P 3M 5d"],Mb6:["1P 3M 13m"],Msus2:["1P 2M 5P",["add9no3","sus2"]],Msus4:["1P 4P 5P",["sus","sus4"]],Maddb9:["1P 3M 5P 9m"],m:["1P 3m 5P"],m11:["1P 3m 5P 7m 9M 11P",["_11"]],m11b5:["1P 3m 7m 12d 2M 4P",["h11","_11b5"]],m13:["1P 3m 5P 7m 9M 11P 13M",["_13"]],m6:["1P 3m 4P 5P 13M",["_6"]],m69:["1P 3m 5P 6M 9M",["_69"]],m7:["1P 3m 5P 7m",["minor7","_","_7"]],m7add11:["1P 3m 5P 7m 11P",["m7add4"]],m7b5:["1P 3m 5d 7m",["half-diminished","h7","_7b5"]],m9:["1P 3m 5P 7m 9M",["_9"]],m9b5:["1P 3m 7m 12d 2M",["h9","-9b5"]],mMaj7:["1P 3m 5P 7M",["mM7","_M7"]],mMaj7b6:["1P 3m 5P 6m 7M",["mM7b6"]],mM9:["1P 3m 5P 7M 9M",["mMaj9","-M9"]],mM9b6:["1P 3m 5P 6m 7M 9M",["mMaj9b6"]],mb6M7:["1P 3m 6m 7M"],mb6b9:["1P 3m 6m 9m"],o:["1P 3m 5d",["mb5","dim"]],o7:["1P 3m 5d 13M",["diminished","m6b5","dim7"]],o7M7:["1P 3m 5d 6M 7M"],oM7:["1P 3m 5d 7M"],sus24:["1P 2M 4P 5P",["sus4add9"]],madd4:["1P 3m 4P 5P"],madd9:["1P 3m 5P 9M"],4:["1P 4P 7m 10m",["quartal"]],5:["1P 5P"],7:["1P 3M 5P 7m",["Dominant","Dom"]],9:["1P 3M 5P 7m 9M",["79"]],11:["1P 5P 7m 9M 11P"],13:["1P 3M 5P 7m 9M 13M",["13_"]],64:["5P 8P 10M"],"M#5":["1P 3M 5A",["augmented","maj#5","Maj#5","+","aug"]],"M#5add9":["1P 3M 5A 9M",["+add9"]],"M13#11":["1P 3M 5P 7M 9M 11A 13M",["maj13#11","Maj13#11","M13+4","M13#4"]],"M6#11":["1P 3M 5P 6M 11A",["M6b5","6#11","6b5"]],"M69#11":["1P 3M 5P 6M 9M 11A"],"M7#11":["1P 3M 5P 7M 11A",["maj7#11","Maj7#11","M7+4","M7#4"]],"M7#5":["1P 3M 5A 7M",["maj7#5","Maj7#5","maj9#5","M7+"]],"M7#5sus4":["1P 4P 5A 7M"],"M7#9#11":["1P 3M 5P 7M 9A 11A"],"M9#11":["1P 3M 5P 7M 9M 11A",["maj9#11","Maj9#11","M9+4","M9#4"]],"M9#5":["1P 3M 5A 7M 9M",["Maj9#5"]],"M9#5sus4":["1P 4P 5A 7M 9M"],"11b9":["1P 5P 7m 9m 11P"],"13#11":["1P 3M 5P 7m 9M 11A 13M",["13+4","13#4"]],"13#9":["1P 3M 5P 7m 9A 13M",["13#9_"]],"13#9#11":["1P 3M 5P 7m 9A 11A 13M"],"13b5":["1P 3M 5d 6M 7m 9M"],"13b9":["1P 3M 5P 7m 9m 13M"],"13b9#11":["1P 3M 5P 7m 9m 11A 13M"],"13no5":["1P 3M 7m 9M 13M"],"13sus4":["1P 4P 5P 7m 9M 13M",["13sus"]],"69#11":["1P 3M 5P 6M 9M 11A"],"7#11":["1P 3M 5P 7m 11A",["7+4","7#4","7#11_","7#4_"]],"7#11b13":["1P 3M 5P 7m 11A 13m",["7b5b13"]],"7#5":["1P 3M 5A 7m",["+7","7aug","aug7"]],"7#5#9":["1P 3M 5A 7m 9A",["7alt","7#5#9_","7#9b13_"]],"7#5b9":["1P 3M 5A 7m 9m"],"7#5b9#11":["1P 3M 5A 7m 9m 11A"],"7#5sus4":["1P 4P 5A 7m"],"7#9":["1P 3M 5P 7m 9A",["7#9_"]],"7#9#11":["1P 3M 5P 7m 9A 11A",["7b5#9"]],"7#9#11b13":["1P 3M 5P 7m 9A 11A 13m"],"7#9b13":["1P 3M 5P 7m 9A 13m"],"7add6":["1P 3M 5P 7m 13M",["67","7add13"]],"7b13":["1P 3M 7m 13m"],"7b5":["1P 3M 5d 7m"],"7b6":["1P 3M 5P 6m 7m"],"7b9":["1P 3M 5P 7m 9m"],"7b9#11":["1P 3M 5P 7m 9m 11A",["7b5b9"]],"7b9#9":["1P 3M 5P 7m 9m 9A"],"7b9b13":["1P 3M 5P 7m 9m 13m"],"7b9b13#11":["1P 3M 5P 7m 9m 11A 13m",["7b9#11b13","7b5b9b13"]],"7no5":["1P 3M 7m"],"7sus4":["1P 4P 5P 7m",["7sus"]],"7sus4b9":["1P 4P 5P 7m 9m",["susb9","7susb9","7b9sus","7b9sus4","phryg"]],"7sus4b9b13":["1P 4P 5P 7m 9m 13m",["7b9b13sus4"]],"9#11":["1P 3M 5P 7m 9M 11A",["9+4","9#4","9#11_","9#4_"]],"9#11b13":["1P 3M 5P 7m 9M 11A 13m",["9b5b13"]],"9#5":["1P 3M 5A 7m 9M",["9+"]],"9#5#11":["1P 3M 5A 7m 9M 11A"],"9b13":["1P 3M 7m 9M 13m"],"9b5":["1P 3M 5d 7m 9M"],"9no5":["1P 3M 7m 9M"],"9sus4":["1P 4P 5P 7m 9M",["9sus"]],"m#5":["1P 3m 5A",["m+","mb6"]],"m11A 5":["1P 3m 6m 7m 9M 11P"],"m7#5":["1P 3m 6m 7m"],"m9#5":["1P 3m 6m 7m 9M"],"+add#9":["1P 3M 5A 9A"]},nt=function(n){return X(n)||Sn(n)||0},tt=function(n){return parseInt(A(n),2)},rt=function(n){return n.replace(/0/g,"").length},et=null,mt=/^[01]{12}$/,it="1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M".split(" "),ut=Object.freeze({chroma:A,chromas:g,modes:j,isChroma:y,intervals:O,isEqual:x,isSubsetOf:_,isSupersetOf:z,includes:q,filter:k}),ot=function(n){var t=Object.keys(n).sort(),r=[],e=[],m=function(n,t,m){r[n]=t,e[m]=e[m]||[],e[m].push(n);};t.forEach(function(t){var r=n[t][0].split(" "),e=n[t][1],i=A(r);m(t,r,i),e&&e.forEach(function(n){return m(n,r,i)});});var i=Object.keys(r).sort(),u=function(n){return r[n]};return u.names=function(n){return "string"==typeof n?(e[n]||[]).slice():(!0===n?i:t).slice()},u},Pt=function(n,t){var r=function(r){return n(r)||t(r)};return r.names=function(r){return n.names(r).concat(t.names(r))},r},Mt=ot(Yn),at=ot(Zn),lt=Pt(Mt,at),ct=Object.freeze({dictionary:ot,combine:Pt,scale:Mt,chord:at,pcset:lt}),st=Object.freeze({name:null,intervals:[],names:[],chroma:null,setnum:null}),ft=function(n,t){return function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=Mt(n);if(!t)return st;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=Mt.names(r.chroma),Object.freeze(r)},{}),dt=Mt.names,pt=function(n){var t=D(n);return ft(t[1]).intervals},bt=function(n){var t=pt(n),r=S(n);return j(t).map(function(n,e){var m=Mt.names(n)[0];if(m)return [r[e]||t[e],m]}).filter(function(n){return n})},ht=function(n){var t=_(pt(n));return at.names().filter(function(n){return t(at(n))})},vt=function(n){var t=Mn(n.map(U));if(!t.length)return t;var r=t[0],e=P(t);return u(e.indexOf(r),e)},At=function(n){if(!pt(n).length)return [];var t=z(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},gt=function(n){var t=_(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},jt=Object.freeze({props:ft,names:dt,intervals:pt,notes:S,exists:w,tokenize:D,modeNames:bt,chords:ht,toScale:vt,supersets:At,subsets:gt}),yt=at.names,Ot=Object.freeze({name:null,names:[],intervals:[],chroma:null,setnum:null}),xt=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=at(n);if(!t)return Ot;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=at.names(r.chroma),r}),_t=function(n){return xt(C(n)[1]).intervals},zt=function(n){return void 0!==at(C(n)[1])},qt=function(n){if(!_t(n).length)return [];var t=z(_t(n));return at.names().filter(function(n){return t(at(n))})},kt=function(n){var t=_(_t(n));return at.names().filter(function(n){return t(at(n))})},St=/^(6|64|7|9|11|13)$/,wt=Object.freeze({names:yt,props:xt,intervals:_t,notes:E,exists:zt,supersets:qt,subsets:kt,tokenize:C}),Dt=l,Et=h,Ct=L,$t=H,Ft=K,Gt=at,It=Mt;n.Array=sn,n.Note=Pn,n.Interval=In,n.Distance=Xn,n.Scale=jt,n.Chord=wt,n.PcSet=ut,n.Dictionary=ct,n.transpose=Dt,n.interval=Et,n.note=Ct,n.midi=$t,n.freq=Ft,n.chord=Gt,n.scale=It,Object.defineProperty(n,"__esModule",{value:!0});})(tonal$1); -//import {Nil} from './type_utils.js'; -class MelodicBeatLiteral { - constructor(opts) { - this.time = opts.time || { time: 'auto' }; - this.pitch = opts.pitch; - this.octave = opts.octave || 'inherit'; - this.scope = null; - this.parentMeasure = null; - this.indexInMeasure = null; - this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation - } - init(scope, parentMeasure, indexInMeasure) { - this.scope = scope; - this.parentMeasure = parentMeasure; - this.indexInMeasure = indexInMeasure; - } - getTime() { - if (this.time.time === 'auto') { - return this.indexInMeasure + 1; - } - else { - return this.time.time; - } - } - /** - * Normalize a chord into a form tonal can handle - * @param {string} [chord=''] - * @return {string} - */ - static normalizeChord(chord = '') { - return chord - .replace(/-/g, '_') // tonal uses _ over - for minor7 - .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? - } - static chordToScaleName(chord) { - let chordType = tonal$1.Chord.tokenize(chord)[1]; - // @TODO: make this more robust - let names = tonal$1.Chord.props(chordType).names; - if (names.includes('dim')) - return 'diminished'; - if (names.includes('aug')) - return 'augmented'; - if (names.includes('Major')) - return 'major'; - if (names.includes('minor')) - return 'minor'; - if (names.includes('minor7')) - return 'dorian'; - if (names.includes('Dominant')) - return 'mixolydian'; - // if none of the above match, do our best to find the closest fit - let closestScale = 'major'; - names.forEach(name => { - if (name.startsWith('dim')) - closestScale = 'diminished'; - if (name.startsWith('aug')) - closestScale = 'augmented'; - if (name.startsWith('M')) - closestScale = 'major'; - if (name.startsWith('m')) - closestScale = 'minor'; - }); - return closestScale; - } - handleInversion(songIterator, pitches) { - let tonicPC = songIterator.song.getTransposedKey(); - let tonicNote = tonal$1.Note.from({ oct: this.getOctave() }, tonicPC); - let tonic = tonal$1.Note.midi(tonicNote); - let outPitches = []; - for (let pitchNote of pitches) { - let pitch = tonal$1.Note.midi(pitchNote); - if (pitch - tonic >= 6) - pitch -= 12; - outPitches.push(tonal$1.Note.fromMidi(pitch)); - } - return outPitches; - } - static getAnchorChord(anchor, songIterator, currentTime) { - let anchorChord; - switch (anchor) { - case 'KEY': { - anchorChord = songIterator.song.getTransposedKey(); - } - case 'NEXT': { - let nextMeasure = songIterator.getRelative(1); - if (nextMeasure) { - anchorChord = nextMeasure.beats[0].chord; - } - else { - anchorChord = songIterator.song.getTransposedKey(); - } +function normalizeChordForTonal(chord = '') { + return chord + .replace(/-/g, '_') // tonal uses _ over - for minor7 + .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? +} +function getAnchorChord(anchor, songIterator, currentTime) { + let anchorChord; + switch (anchor) { + case 'KEY': { + anchorChord = songIterator.song.getTransposedKey(); + } + case 'NEXT': { + let nextMeasure = songIterator.getRelative(1); + if (nextMeasure) { + anchorChord = nextMeasure.beats[0].chord; } - case 'STEP': - case 'ARPEGGIATE': - default: { - // crawl backward through this measure to get the last set beat - let lastSetBeat = Math.floor(currentTime); - let iteratorMeasure = songIterator.getRelative(0); - if (!iteratorMeasure) - break; - do { - const beat = iteratorMeasure.beats[lastSetBeat]; - anchorChord = beat && beat.chord; - lastSetBeat--; - } while (!anchorChord); + else { + anchorChord = songIterator.song.getTransposedKey(); } } - return this.normalizeChord(anchorChord); - } - static anchorChordToRoot(anchorChord, degree, octave) { - let anchorTonic = tonal$1.Chord.tokenize(anchorChord)[0]; - let anchorScaleName = this.chordToScaleName(anchorChord); - let scalePCs = tonal$1.Scale.notes(anchorTonic, anchorScaleName); - let rootPC = scalePCs[degree - 1]; - return tonal$1.Note.from({ oct: octave }, rootPC); - } - getAnchorData(songIterator) { - let anchorChord = MelodicBeatLiteral.getAnchorChord(this.pitch.anchor, songIterator, this.getTime()); - let root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, this.pitch.degree, this.getOctave()); - return [anchorChord, root]; - } - getPitches(songIterator) { - let [anchorChord, root] = this.getAnchorData(songIterator); - let pitches; - if (this.pitch.chord) { - // this feels extremely incorrect - // why would anyone need it to work this way - let anchorChordType = tonal$1.Chord.tokenize(anchorChord)[1]; - pitches = tonal$1.Chord.notes(root, anchorChordType); - } - else { - pitches = [root]; - } - if (this.scope.vars.get('invertible')) { - pitches = this.handleInversion(songIterator, pitches); - } - return pitches; - } - /** - * Returns true if the beat is anchored via STEP or ARPEGGIATE - * @returns {boolean} - */ - isDynamic() { - return ['STEP', 'ARPEGGIATE'].includes(this.pitch.anchor); - } - getOctave() { - if (this.octave === 'inherit') { - return this.scope.vars.get('octave'); - } - else { - return this.octave; - } + case 'STEP': + case 'ARPEGGIATE': + default: { + // crawl backward through this measure to get the last set beat + let lastSetBeat = Math.floor(currentTime); + let iteratorMeasure = songIterator.getRelative(0); + if (!iteratorMeasure) + break; + do { + const beat = iteratorMeasure.beats[lastSetBeat]; + anchorChord = beat && beat.chord; + lastSetBeat--; + } while (!anchorChord); + } + } + return normalizeChordForTonal(anchorChord); +} +function anchorChordToRoot(anchorChord, degree, octave) { + let anchorTonic = tonal$1.Chord.tokenize(anchorChord)[0]; + let anchorScaleName = chordToScaleName(anchorChord); + let scalePCs = tonal$1.Scale.notes(anchorTonic, anchorScaleName); + let rootPC = scalePCs[degree - 1]; + return tonal$1.Note.from({ oct: octave }, rootPC); +} +function chordToScaleName(chord) { + let chordType = tonal$1.Chord.tokenize(chord)[1]; + // @TODO: make this more robust + let names = tonal$1.Chord.props(chordType).names; + if (names.includes('dim')) + return 'diminished'; + if (names.includes('aug')) + return 'augmented'; + if (names.includes('Major')) + return 'major'; + if (names.includes('minor')) + return 'minor'; + if (names.includes('minor7')) + return 'dorian'; + if (names.includes('Dominant')) + return 'mixolydian'; + // if none of the above match, do our best to find the closest fit + let closestScale = 'major'; + names.forEach(name => { + if (name.startsWith('dim')) + closestScale = 'diminished'; + if (name.startsWith('aug')) + closestScale = 'augmented'; + if (name.startsWith('M')) + closestScale = 'major'; + if (name.startsWith('m')) + closestScale = 'minor'; + }); + return closestScale; +} + +const anchorReverseMap = { 'KEY': 'k', 'NEXT': 'n', 'STEP': 's', 'ARPEGGIATE': 'a' }; +class PlaybackAnchorValue { + constructor(value) { + this.type = 'anchor'; + this.value = value; } - getDuration() { - let duration; - duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); - if (this.time.flag === 'STACCATO') { - return Math.min(0.25, duration); - } - else { - return duration; - } + toBoolean() { return true; } + toOutputString() { return anchorReverseMap[this.value]; } +} +class PlaybackBeatValue { + constructor() { + this.type = null; } - getVolume() { - let volume = this.scope.vars.get('volume'); - if (this.time.flag === 'ACCENTED') - volume = Math.min(1, volume += .1); - return volume; + toBoolean() { return true; } +} +class PlaybackMelodicBeatValue extends PlaybackBeatValue { + constructor(time = { time: 'auto' }, pitch, octave = 'inherit') { + super(); + this.type = 'melodic_beat'; + this.value = { + time: null, + pitch: null, + octave: null, + }; + this.value.time = time; + this.value.pitch = pitch; + this.value.octave = octave; + } + toOutputString() { + const timeFlag = this.time.flag ? (this.time.flag === 'ACCENTED' ? 'a' : 's') : ''; + const timePart = `${this.time.time === 'auto' ? '' : this.time.time}${timeFlag}`; + const pitchAnchor = this.pitch.anchor ? anchorReverseMap[this.pitch.anchor] : ''; + const pitchRoll = this.pitch.roll ? (this.pitch.roll === 'ROLL_UP' ? 'r' : 'rd') : ''; + const pitchPart = `:${pitchAnchor}${this.pitch.degree || ''}${this.pitch.chord ? 'c' : ''}${pitchRoll}`; + const octavePart = this.octave === 'inherit' ? '' : `:${this.octave}`; + return `${timePart}${pitchPart}${octavePart}`; + } + get time() { return this.value.time; } + get pitch() { return this.value.pitch; } + get octave() { return this.value.octave; } +} +class PlaybackDrumBeatValue extends PlaybackBeatValue { + constructor(time, accented = false) { + super(); + this.type = 'drum_beat'; + this.value = { + time: null, + accented: null, + }; + this.value.time = time; + this.value.accented = accented; } - execute(songIterator) { - let notes = new NoteSet(); - let time = this.getTime(); // @TODO: this varies with rolling - let pitches = this.getPitches(songIterator); - let duration = this.getDuration(); // @TODO: this varies with rolling - let volume = this.getVolume(); - for (let pitch of pitches) { - notes.push(new Note({ - time: time, - pitch: pitch, - duration: duration, - volume: volume - })); - } - return notes; + toOutputString() { + return `${this.time}${this.accented ? 'a' : ''}`; } + get time() { return this.value.time; } + get accented() { return this.value.accented; } } -class DrumBeatLiteral { - constructor(opts) { - this.time = opts.time; - this.accented = opts.accented || false; - this.scope = null; - this.parentMeasure = null; - this.indexInMeasure = null; - } - init(scope, parentMeasure, indexInMeasure) { - this.scope = scope; - this.parentMeasure = parentMeasure; - this.indexInMeasure = indexInMeasure; + +class PlaybackNilValue { + constructor() { + this.type = 'Nil'; + this.value = null; } - getTime() { - return this.time; + toBoolean() { return false; } + toOutputString() { return 'Nil'; } +} +class PlaybackStringValue { + constructor(value) { + this.type = 'string'; + this.value = value; } - getDuration() { - let duration; - duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); - return duration; + toBoolean() { return this.value !== ''; } + toOutputString() { + // @TODO: store raw value from tokenizer? (which may not always exist for programmatically-generated strings) + // At least this is consistent... + return `"${this.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`; } - getVolume() { - let volume = this.scope.vars.get('volume'); - if (this.accented) - volume = Math.min(1, volume += .1); - return volume; +} +class PlaybackNumberValue { + constructor(value) { + this.type = 'number'; + this.value = value; + } + toInteger() { return Math.floor(this.value); } + toBoolean() { return this.value !== 0; } + toOutputString() { return this.value.toString(); } +} +class PlaybackBooleanValue { + constructor(value) { + this.type = 'boolean'; + this.value = value; } - execute(songIterator) { - let time = this.getTime(); - let duration = this.getDuration(); - let volume = this.getVolume(); - return new NoteSet(new Note({ - time: time, - pitch: AwaitingDrum, - duration: duration, - volume: volume - })); + toBoolean() { return this.value; } + toOutputString() { return this.value ? 'true' : 'false'; } +} +class PlaybackTimeSignatureValue { + constructor(value) { + this.type = 'time_signature'; + this.value = value; } + toBoolean() { return true; } + toOutputString() { return `${this.value[0]} / ${this.value[1]}`; } } let definitions = new Map(); @@ -1506,38 +1450,25 @@ function assertArgTypes(identifier, args, types, scope) { if (types == '*') return; if (args.length != types.length) { - throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, scope); + throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, args, scope); } for (let i in args) { if (types[i] == '*') continue; let arg = args[i]; if (arg instanceof FunctionCall) { - arg = arg.returns; - if (arg == '*') { + if (arg.returns == '*') { continue; // what's the correct functionality here? cry? } - else if (typeof types[i] == 'string') { - if (arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); - } - } else { - if (arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); + if (arg.returns !== types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, args, scope); } } } else { - if (typeof types[i] == 'string') { - if (typeof arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); - } - } - else { - if (!(arg instanceof types[i])) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); - } + if (arg.type !== types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, args, scope); } } } @@ -1610,7 +1541,7 @@ let define$1 = function (identifier, opts, func) { scope: opts.scope || 'no-meta', execute: (args, songIterator, scope) => { let argErr = message => { - throw new FunctionArgumentsError(message, scope); + throw new FunctionArgumentsError(message, args, scope); }; return func(args, songIterator, scope, argErr); } @@ -1630,11 +1561,11 @@ let defineVar = function (identifier, type, goalscope = null) { let opts = { types: [type], scope: goalscope, - returns: Nil + returns: 'Nil' }; define$1(identifier, opts, (args, songIterator, scope, argErr) => { scope.vars.set(identifier, args[0]); - return Nil; + return new PlaybackNilValue(); }); }; /** @@ -1648,8 +1579,8 @@ let defineVar = function (identifier, type, goalscope = null) { let defineBoolean = function (identifier, goalscope = null) { let opts = { types: '*', - scopes: goalscope, - returns: Nil + scope: goalscope, + returns: 'Nil' }; define$1(identifier, opts, (args, songIterator, scope, argErr) => { if (args.length) { @@ -1657,9 +1588,9 @@ let defineBoolean = function (identifier, goalscope = null) { scope.vars.set(identifier, args[0]); } else { - scope.vars.set(identifier, true); + scope.vars.set(identifier, new PlaybackBooleanValue(true)); } - return Nil; + return new PlaybackNilValue; }); }; /*********** ACTUAL FUNCTION DEFINITIONS ***********/ @@ -1672,38 +1603,42 @@ defineVar('playback-version', 'number', 'meta'); define$1('time-signature', { types: ['number', 'number'], scope: 'options', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (!Number.isInteger(Math.log2(args[1]))) { - argErr(`Argument 2 of "time-signature" must be a power of 2 (got ${args}).`); + const value1 = args[0].value; + const value2 = args[1].value; + if (!Number.isInteger(Math.log2(value1))) { + argErr(`Argument 2 of "time-signature" must be a power of 2`); } - scope.vars.set('time-signature', [args[0], args[1]]); - return Nil; + scope.vars.set('time-signature', new PlaybackTimeSignatureValue([value1, value2])); + return new PlaybackNilValue(); }); defineBoolean('swing', 'options'); /*** anywhere but @meta functions ***/ define$1('volume', { types: ['number'], scope: 'no-meta', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (args[0] < 0 || args[0] > 1) { - argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive) (got ${args}).`); + const { value } = args[0]; + if (value < 0 || value > 1) { + argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive)`); } scope.vars.set('volume', args[0]); - return Nil; + return new PlaybackNilValue(); }); defineBoolean('invertible', 'no-meta'); define$1('octave', { types: ['number'], scope: 'no-meta', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { - argErr(`Argument 1 of "octave" must be an integer 0-9 (got ${args}).`); + const { value } = args[0]; + if (!Number.isInteger(value) || value < 0 || value > 9) { + argErr(`Argument 1 of "octave" must be an integer 0-9`); } scope.vars.set('octave', args[0]); - return Nil; + return new PlaybackNilValue(); }); /*** anywhere but config functions (strictly dynamic functions) ***/ define$1('choose', { @@ -1711,24 +1646,24 @@ define$1('choose', { scope: 'no-config', returns: '*' }, (args, songIterator, scope, argErr) => { - let nonNilArgs = args.filter(arg => arg !== Nil); + let nonNilArgs = args.filter(arg => arg.type !== 'Nil'); if (nonNilArgs.length) { let index = Math.floor(Math.random() * nonNilArgs.length); return nonNilArgs[index]; } else { - return Nil; + return new PlaybackNilValue(); } }); let anchorOrNumberToChordAndRoot = function (arg, songIterator) { let anchorChord, root; - if (typeof arg == 'number') { - anchorChord = MelodicBeatLiteral.getAnchorChord(null, songIterator, 1); - root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, arg, 4); + if (arg.type === 'number') { + anchorChord = getAnchorChord(null, songIterator, 1); + root = anchorChordToRoot(anchorChord, arg.value, 4); } - else if (arg.anchor) { - anchorChord = MelodicBeatLiteral.getAnchorChord(arg.anchor, songIterator, 1); - root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, 1, 4); + else { + anchorChord = getAnchorChord(arg.value, songIterator, 1); + root = anchorChordToRoot(anchorChord, 1, 4); } return [anchorChord, root]; }; @@ -1738,34 +1673,34 @@ define$1('progression', { returns: 'boolean' }, (args, songIterator, scope, argErr) => { for (let i in args) { - let arg = args[i]; - let [, goal] = anchorOrNumberToChordAndRoot(arg, songIterator); - if (!goal) { - argErr(`Arguments of "progression" must be numbers or anchors (got "${args}").`); + if (args[0].type !== 'number' && args[0].type !== 'anchor') { + argErr(`Arguments of "progression" must be numbers or anchors`); } - let actualMeasure = songIterator.getRelative(Number(i)); + const [, goal] = anchorOrNumberToChordAndRoot(args[0], songIterator); + const actualMeasure = songIterator.getRelative(Number(i)); if (!actualMeasure) - return false; - let actualChord = MelodicBeatLiteral.normalizeChord(actualMeasure.beats[0].chord); - let actual = MelodicBeatLiteral.anchorChordToRoot(actualChord, 1, 4); + return new PlaybackBooleanValue(false); + const actualChord = normalizeChordForTonal(actualMeasure.beats[0].chord); + const actual = anchorChordToRoot(actualChord, 1, 4); if (actual != goal) - return false; + return new PlaybackBooleanValue(false); } - return true; + return new PlaybackBooleanValue(true); }); define$1('in-scale', { types: '*', scope: 'no-config', returns: 'boolean' }, (args, songIterator, scope, argErr) => { + if ((args[0].type !== 'number' && args[0].type !== 'anchor') + || args[1].type !== 'number' && args[1].type !== 'anchor') { + argErr(`Arguments of "in-scale" must be numbers or anchors`); + } let [, note] = anchorOrNumberToChordAndRoot(args[0], songIterator); let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); - if (!note || !goalChord) { - argErr(`Arguments of "in-scale" must be numbers or anchors (got ${args}).`); - } - let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); + let goalScaleName = chordToScaleName(goalChord); let goalScale = tonal$1.Scale.notes(goalTonic, goalScaleName); - return goalScale.includes(note); + return new PlaybackBooleanValue(goalScale.includes(note)); }); define$1('beat-defined', { types: ['number'], @@ -1774,8 +1709,9 @@ define$1('beat-defined', { }, (args, songIterator, scope, argErr) => { let measure = songIterator.getRelative(0); if (!measure) - return false; - return measure.beats[args[0]].chord !== null; + return new PlaybackBooleanValue(false); + const index = args[0].value; + return new PlaybackBooleanValue(measure.beats[index].chord !== null); }); /*** pattern-only functions ***/ defineBoolean('private', 'pattern'); @@ -1783,13 +1719,13 @@ defineVar('length', 'number', 'pattern'); define$1('chance', { types: ['number'], scope: 'pattern', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (args[0] < 0 || args[0] > 1) { - argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive) (got ${args}).`); + if (args[0].value < 0 || args[0].value > 1) { + argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive)`); } scope.vars.set('chance', args[0]); - return Nil; + return new PlaybackNilValue(); }); /** @@ -1852,8 +1788,8 @@ class PatternExpressionGroup extends Scope { super(); this.type = 'PatternExpressionGroup'; this.name = '@pattern()'; - this.defaultVars.set('private', false); - this.defaultVars.set('chance', 1); + this.defaultVars.set('private', new PlaybackBooleanValue(false)); + this.defaultVars.set('chance', new PlaybackNumberValue(1)); this.expressions = expressions; this.functionCalls = []; this.nonFunctionCallExpressions = []; @@ -1886,25 +1822,25 @@ class PatternExpressionGroup extends Scope { } execute(songIterator, callerIsTrack = false) { this.inherit(); - let beats = Nil; + let beats = null; for (let function_call of this.functionCalls) { let return_value = function_call.execute(songIterator); if (return_value instanceof NoteSet) { - if (beats !== Nil) { + if (beats) { throw new TooManyBeatsError(this); } beats = return_value; } } - if (callerIsTrack && this.vars.get('private') === true) { - return Nil; // if it's private we can give up now + if (callerIsTrack && this.vars.get('private').value === true) { + return null; // if it's private we can give up now } for (let expression of this.nonFunctionCallExpressions) { if (expression.execute) { expression = expression.execute(songIterator); } if (expression instanceof NoteSet) { - if (beats !== Nil) { + if (beats) { throw new TooManyBeatsError(this); } beats = expression; @@ -1926,7 +1862,7 @@ class PatternStatement extends PatternExpressionGroup { this.condition = (opts.condition !== undefined) ? opts.condition : null; } getChance() { - return this.vars.get('chance'); + return this.vars.get('chance').value; } link(ASTs, parentStyle, parentTrack) { super.link(ASTs, parentStyle, parentTrack); @@ -1948,8 +1884,8 @@ class PatternStatement extends PatternExpressionGroup { else { condition_value = this.condition; } - if (cast_bool(condition_value) === false) - return Nil; + if (condition_value.toBoolean() === false) + return null; } return super.execute(songIterator, callerIsTrack); } @@ -1966,7 +1902,7 @@ class PatternCall { this.pattern; } getChance() { - return this.patternStatement.getChance()(); + return this.patternStatement.getChance(); } init(scope) { this.scope = scope; @@ -2032,7 +1968,7 @@ class JoinedPatternExpression { return (new NoteSet()).concat(...noteSets); } else { - return Nil; + return null; } } } @@ -2042,9 +1978,9 @@ class TrackStatement extends Scope { super(); this.name = opts.identifier; this.type = '@track'; - this.defaultVars.set('octave', 4); - this.defaultVars.set('volume', 1); - this.defaultVars.set('private', false); + this.defaultVars.set('octave', new PlaybackNumberValue(4)); + this.defaultVars.set('volume', new PlaybackNumberValue(1)); + this.defaultVars.set('private', new PlaybackBooleanValue(false)); this.instrument = opts.instrument; this.identifier = opts.identifier; this.members = opts.members; @@ -2094,7 +2030,7 @@ class TrackStatement extends Scope { let result = pattern.execute(songIterator, true); console.log(' - Result:', result); // @TODO: handle multi-measure patterns (via locks?) - if (result !== Nil) { + if (result) { for (let note of result) { if (note.pitch === AwaitingDrum) { throw new DrumBeatInMelodicBeatGroupError(pattern); @@ -2117,8 +2053,8 @@ class TrackStatement extends Scope { return option.noteSet; } } - console.log(' - Final result:', Nil); - return Nil; + console.log(' - Final result:', null); + return null; } } class TrackCall { @@ -2141,8 +2077,8 @@ class GlobalScope extends Scope { } init() { // set some default values - this.vars.set('time-signature', [4, 4]); - this.vars.set('tempo', 120); + this.vars.set('time-signature', new PlaybackTimeSignatureValue([4, 4])); + this.vars.set('tempo', new PlaybackNumberValue(120)); this.tracks = new Map(); this.metaStatements = []; // @TODO: stop circular dependencies? cache them and mark one as mom @@ -2192,7 +2128,7 @@ class GlobalScope extends Scope { let trackNoteMap = new Map(); for (let [, track] of this.tracks) { let trackNotes = track.execute(songIterator); - if (trackNotes !== Nil) + if (trackNotes) trackNoteMap.set(track.instrument, trackNotes); } return trackNoteMap; @@ -2206,11 +2142,6 @@ class GlobalScope extends Scope { } } -class AnchorArgument { - constructor(anchor) { - this.anchor = anchor; - } -} class BooleanOperator { constructor(...args) { this.args = args; @@ -2245,7 +2176,7 @@ class BooleanNot extends BooleanOperator { } execute(songIterator) { let args = this.resolve_args(songIterator); - return !cast_bool(args[0]); + return new PlaybackBooleanValue(!args[0].toBoolean()); } } class BooleanAnd extends BooleanOperator { @@ -2256,7 +2187,7 @@ class BooleanAnd extends BooleanOperator { // sorry no short-circuiting because this code is prettier // @TODO: add short-circuiting if this actually makes it too slow let args = this.resolve_args(songIterator); - return cast_bool(args[0]) && cast_bool(args[1]); + return new PlaybackBooleanValue(args[0].toBoolean() && args[1].toBoolean()); } } class BooleanOr extends BooleanOperator { @@ -2265,7 +2196,150 @@ class BooleanOr extends BooleanOperator { } execute(songIterator) { let args = this.resolve_args(songIterator); - return cast_bool(args[0]) || cast_bool(args[1]); + return new PlaybackBooleanValue(args[0].toBoolean() || args[1].toBoolean()); + } +} + +class MelodicBeatLiteral { + constructor(opts) { + this.value = new PlaybackMelodicBeatValue(opts.time, opts.pitch, opts.octave); + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + if (this.value.time.time === 'auto') { + return this.indexInMeasure + 1; + } + else { + return this.value.time.time; + } + } + handleInversion(songIterator, pitches) { + let tonicPC = songIterator.song.getTransposedKey(); + let tonicNote = tonal$1.Note.from({ oct: this.getOctave() }, tonicPC); + let tonic = tonal$1.Note.midi(tonicNote); + let outPitches = []; + for (let pitchNote of pitches) { + let pitch = tonal$1.Note.midi(pitchNote); + if (pitch - tonic >= 6) + pitch -= 12; + outPitches.push(tonal$1.Note.fromMidi(pitch)); + } + return outPitches; + } + getAnchorData(songIterator) { + let anchorChord = getAnchorChord(this.value.pitch.anchor, songIterator, this.getTime()); + let root = anchorChordToRoot(anchorChord, this.value.pitch.degree, this.getOctave()); + return [anchorChord, root]; + } + getPitches(songIterator) { + let [anchorChord, root] = this.getAnchorData(songIterator); + let pitches; + if (this.value.pitch.chord) { + // this feels extremely incorrect + // why would anyone need it to work this way + let anchorChordType = tonal$1.Chord.tokenize(anchorChord)[1]; + pitches = tonal$1.Chord.notes(root, anchorChordType); + } + else { + pitches = [root]; + } + if (this.scope.vars.get('invertible')) { + pitches = this.handleInversion(songIterator, pitches); + } + return pitches; + } + /** + * Returns true if the beat is anchored via STEP or ARPEGGIATE + * @returns {boolean} + */ + isDynamic() { + return ['STEP', 'ARPEGGIATE'].includes(this.value.pitch.anchor); + } + getOctave() { + if (this.value.octave === 'inherit') { + return this.scope.vars.get('octave').value; + } + else { + return this.value.octave; + } + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + if (this.value.time.flag === 'STACCATO') { + return Math.min(0.25, duration); + } + else { + return duration; + } + } + getVolume() { + let volume = this.scope.vars.get('volume').value; + if (this.value.time.flag === 'ACCENTED') + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let notes = new NoteSet(); + let time = this.getTime(); // @TODO: this varies with rolling + let pitches = this.getPitches(songIterator); + let duration = this.getDuration(); // @TODO: this varies with rolling + let volume = this.getVolume(); + for (let pitch of pitches) { + notes.push(new Note({ + time: time, + pitch: pitch, + duration: duration, + volume: volume + })); + } + return notes; + } +} +class DrumBeatLiteral { + constructor(opts) { + this.value = new PlaybackDrumBeatValue(opts.time, opts.accented); + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + return this.value.time; + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + return duration; + } + getVolume() { + let volume = this.scope.vars.get('volume').value; + if (this.value.accented) + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let time = this.getTime(); + let duration = this.getDuration(); + let volume = this.getVolume(); + return new NoteSet(new Note({ + time: time, + pitch: AwaitingDrum, + duration: duration, + volume: volume + })); } } @@ -2284,8 +2358,8 @@ class BeatGroupLiteral { for (let i = 0; i < this.measures.length; i++) { let offset = i * 4; // @TODO: pull in actual meter somehow let measureNotes = this.measures[i].execute(songIterator); - if (measureNotes === Nil) - return Nil; // lets a/s abort the beatgroup + if (measureNotes === null) + return null; // lets a/s abort the beatgroup for (let measureNote of measureNotes) { measureNote.time += offset; joinedMeasures.push(measureNote); @@ -2310,7 +2384,7 @@ class BeatGroupLiteral { // later if it's a multi-measure beatgroup) // @TODO: wtf? const nextMeasure = songIterator.getRelative(1); - return MelodicBeatLiteral.normalizeChord(nextMeasure && nextMeasure.beats[0].chord); + return normalizeChordForTonal(nextMeasure && nextMeasure.beats[0].chord); } } class Measure { @@ -2355,8 +2429,8 @@ class Measure { let joined = new NoteSet(); for (let beat of this.beats) { let notes = beat.execute(songIterator); - if (notes === Nil) - return Nil; // lets a and s abort the beatgroup. + if (!notes) + return null; // lets a and s abort the beatgroup. joined.push(...notes); } return joined; @@ -2456,11 +2530,11 @@ let ParserRules = [ {"name": "FunctionCallExpression$macrocall$1", "symbols": ["FunctionCallExpression$macrocall$2", "FunctionCallExpression$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, "_?", "FunctionCallExpression$macrocall$1", "_?", {"literal":")"}], "postprocess": d => new FunctionCall(d[0], d[4])}, {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, {"literal":")"}], "postprocess": d => new FunctionCall(d[0], [])}, - {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": d => new PlaybackNumberValue(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": d => new PlaybackStringValue(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": d => new PlaybackBooleanValue(d[0])}, {"name": "FunctionCallArgument", "symbols": ["PatternExpression"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new AnchorArgument(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new PlaybackAnchorValue(d[0])}, {"name": "FunctionCallArgument", "symbols": [{"literal":"not"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanNot(d[2])}, {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"and"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanAnd(d[0], d[4])}, {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"or"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanOr(d[0], d[4])}, diff --git a/dist/playback.node.mjs b/dist/playback.node.mjs index 44083c0..9681e06 100644 --- a/dist/playback.node.mjs +++ b/dist/playback.node.mjs @@ -970,16 +970,6 @@ var lexer = moo.states({ } }); -let Nil = Symbol('Nil'); -let cast_bool = function (arg) { - if (arg === Nil || arg === false) { - return false; - } - else { - return true; - } -}; - // does this have to be an Error? idc class PlaybackError extends Error { constructor(message, scope) { @@ -1019,8 +1009,8 @@ class FunctionScopeError extends PlaybackError { } } class FunctionArgumentsError extends PlaybackError { - constructor(message, scope) { - super(message, scope); + constructor(message, args, scope) { + super(`${message} (got ${args.map(a => a.toOutputString()).join(', ')})`, scope); } } /* Pattern-related errors */ @@ -1242,230 +1232,184 @@ class NoteSet extends Array { let tonal$1 = {}; (function(n){function t(n){"string"!=typeof n&&(n="");var t=T.exec(n);return t?[t[1].toUpperCase(),t[2].replace(/x/g,"##"),t[3],t[4]]:null}function r(n,t){return n=Math.round(n),(!0===t?G:I)[n%12]+(Math.floor(n/12)-1)}function e(n,t){for(var r=[];t--;r[t]=t+n);return r}function m(n,t){for(var r=[];t--;r[t]=n-t);return r}function i(n,t){return null===n||null===t?[]:nan(t)})}function P(n){return o(n).filter(function(n,t,r){return 0===t||n!==r[t-1]})}function M(n){return "string"!=typeof n?An:_n[n]||(_n[n]=xn(n))}function a(n){var t=(n+1)%7;return t<0?7+t:t}function l(n,t){if(1===arguments.length)return function(t){return l(n,t)};var r=Kn(n),e=Qn(t);if(null===r||null===e)return null;var m=1===r.length?[r[0]+e[0]]:[r[0]+e[0],r[1]+e[1]];return mn(Un(m[0],m[1]))}function c(n,t){if(1===arguments.length)return function(t){return c(n,t)};var r=Kn(n);return null===r?null:mn(Un(r[0]+t))}function s(n,t){if(1===arguments.length)return function(t){return s(n,t)};var r=Kn(n),e=Kn(t);return null===e||null===r?null:e[0]-r[0]}function f(n,t){return 1===arguments.length?function(t){return l(t,n)}:l(t,n)}function d(n,t,r){var e=Qn(n),m=Qn(t);if(null===e||null===m)return null;var i=[e[0]+r*m[0],e[1]+r*m[1]];return Dn(Wn(i))}function p(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,1)}function b(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,-1)}function h(n,t){if(1===arguments.length)return function(t){return h(n,t)};var r=Kn(n),e=Kn(t);if(null===r||null===e||r.length!==e.length)return null;var m=1===r.length?[e[0]-r[0],-Math.floor(7*(e[0]-r[0])/12)]:[e[0]-r[0],e[1]-r[1]];return Dn(Wn(m))}function v(n,t){if(1===arguments.length)return function(t){return v(n,t)};var r=L(n),e=L(t);return null!==r.midi&&null!==e.midi?e.midi-r.midi:null!==r.chroma&&null!==e.chroma?(e.chroma-r.chroma+12)%12:null}function A(n){if(y(n))return n;if(!Array.isArray(n))return "";var t=[0,0,0,0,0,0,0,0,0,0,0,0];return n.map(nt).forEach(function(n){t[n]=1;}),t.join("")}function g(n){return et=et||i(2048,4095).map(function(n){return n.toString(2)}),"number"==typeof n?et.filter(function(t){return rt(t)===n}):et.slice()}function j(n,t){t=!1!==t;var r=A(n).split("");return Mn(r.map(function(n,e){var m=u(e,r);return t&&"0"===m[0]?null:m.join("")}))}function y(n){return mt.test(n)}function O(n){return y(n)?Mn(n.split("").map(function(n,t){return "1"===n?it[t]:null})):[]}function x(n,t){return 1===arguments.length?function(t){return x(n,t)}:A(n)===A(t)}function _(n,t){return arguments.length>1?_(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t&n)===t})}function z(n,t){return arguments.length>1?z(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t|n)===t})}function q(n,t){return arguments.length>1?q(n)(t):(n=A(n),function(t){return "1"===n[nt(t)]})}function k(n,t){return 1===arguments.length?function(t){return k(n,t)}:t.filter(q(n))}function S(n,t){var r=D(n);return t=t||r[1],pt(t).map(l(r[0]))}function w(n){var t=D(n);return void 0!==Mt(t[1])}function D(n){if("string"!=typeof n)return ["",""];var t=n.indexOf(" "),r=R(n.substring(0,t))||R(n)||"",e=""!==r?n.substring(r.length+1):n;return [r,e.length?e:""]}function E(n,t){var r=C(n);return t=t||r[1],xt(t).intervals.map(l(r[0]))}function C(n){var r=t(n);return ""===r[0]?["",n]:"A"===r[0]&&"ug"===r[3]?["","aug"]:St.test(r[2])?[r[0]+r[1],r[2]+r[3]]:[r[0]+r[1]+r[2],r[3]]}var $="C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B".split(" "),F=function(n){return "string"!=typeof n?$.slice():$.filter(function(t){var r=t[1]||" ";return -1!==n.indexOf(r)})},G=F(" #"),I=F(" b"),T=/^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)$/,B=Object.freeze({pc:null,name:null,step:null,alt:null,oct:null,octStr:null,chroma:null,midi:null,freq:null}),N=[0,2,4,5,7,9,11],L=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var r=t(n);if(""===r[0]||""!==r[3])return B;var e=r[0],m=r[1],i=r[2],u={letter:e,acc:m,octStr:i};return u.pc=u.letter+u.acc,u.name=u.pc+i,u.step=(u.letter.charCodeAt(0)+3)%7,u.alt="b"===u.acc[0]?-u.acc.length:u.acc.length,u.oct=i.length?+i:null,u.chroma=(N[u.step]+u.alt+120)%12,u.midi=null!==u.oct?N[u.step]+u.alt+12*(u.oct+1):null,u.freq=J(u.midi),Object.freeze(u)}),R=function(n){return L(n).name},U=function(n){return L(n).pc},H=function(n){return L(n).midi||+n||null},J=function(n,t){return void 0===t&&(t=440),"number"==typeof n?Math.pow(2,(n-69)/12)*t:null},K=function(n){return L(n).freq||J(n)},Q=Math.log(2),V=Math.log(440),W=function(n){var t=12*(Math.log(n)-V)/Q+69;return Math.round(100*t)/100},X=function(n){return L(n).chroma},Y=function(n){return L(n).oct},Z=function(n){return "CDEFGAB"[n]},nn=function(n,t){return Array(t+1).join(n)},tn=function(n,t){return "number"!=typeof n?"":t(n)},rn=function(n){return tn(n,function(n){return n<0?nn("b",-n):nn("#",n)})},en=function(n,t){void 0===n&&(n={}),void 0===t&&(t=null);var r=t?Object.assign({},L(t),n):n,e=r.step,m=r.alt,i=r.oct,u=Z(e);if(!u)return null;var o=u+rn(m);return i||0===i?o+i:o},mn=en,un=function(n,t){var e=L(n),m=e.alt,i=e.chroma,u=e.midi;if(null===i)return null;var o=!1===t?m<0:m>0;return null===u?U(r(i,o)):r(u,o)},on=function(n){return un(n,!1)},Pn=Object.freeze({names:F,tokenize:t,props:L,name:R,pc:U,midi:H,midiToFreq:J,freq:K,freqToMidi:W,chroma:X,oct:Y,stepToLetter:Z,altToAcc:rn,from:en,build:mn,fromMidi:r,simplify:un,enharmonic:on}),Mn=function(n){return n.filter(function(n){return 0===n||n})},an=function(n){var t=H(n);return null!==t?t:H(n+"-100")},ln=function(n,t){void 0===t&&(t=Math.random);for(var r,e,m=n.length;m;)r=t()*m--|0,e=n[m],n[m]=n[r],n[r]=e;return n},cn=function(n){return 0===n.length?[[]]:cn(n.slice(1)).reduce(function(t,r){return t.concat(n.map(function(t,e){var m=r.slice();return m.splice(e,0,n[0]),m}))},[])},sn=Object.freeze({range:i,rotate:u,compact:Mn,sort:o,unique:P,shuffle:ln,permutations:cn}),fn=new RegExp("^([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})|(AA|A|P|M|m|d|dd)([-+]?\\d+)$"),dn=[0,2,4,5,7,9,11],pn=[0,1,2,3,4,5,6,5,4,3,2,1],bn="1P 2m 2M 3m 3M 4P 5P 6m 6M 7m 7M 8P".split(" "),hn=function(n){return "string"!=typeof n?bn.slice():bn.filter(function(t){return -1!==n.indexOf(t[1])})},vn=function(n){var t=fn.exec(n);return null===t?null:t[1]?[t[1],t[2]]:[t[4],t[3]]},An=Object.freeze({name:null,num:null,q:null,step:null,alt:null,dir:null,type:null,simple:null,semitones:null,chroma:null}),gn=function(n,t){return Array(Math.abs(t)+1).join(n)},jn=function(n,t){return "M"===t&&"M"===n?0:"P"===t&&"P"===n?0:"m"===t&&"M"===n?-1:/^A+$/.test(t)?t.length:/^d+$/.test(t)?"P"===n?-t.length:-t.length-1:null},yn=function(n,t){return 0===t?"M"===n?"M":"P":-1===t&&"M"===n?"m":t>0?gn("A",t):t<0?gn("d","P"===n?t:t+1):null},On=function(n){return (Math.abs(n)-1)%7},xn=function(n){var t=vn(n);if(null===t)return An;var r={num:+t[0],q:t[1]};return r.step=On(r.num),r.type="PMMPPMM"[r.step],"M"===r.type&&"P"===r.q?An:(r.name=""+r.num+r.q,r.dir=r.num<0?-1:1,r.simple=8===r.num||-8===r.num?r.num:r.dir*(r.step+1),r.alt=jn(r.type,r.q),r.oct=Math.floor((Math.abs(r.num)-1)/7),r.semitones=r.dir*(dn[r.step]+r.alt+12*r.oct),r.chroma=(r.dir*(dn[r.step]+r.alt)%12+12)%12,Object.freeze(r))},_n={},zn=function(n){return M(n).num},qn=function(n){return M(n).name},kn=function(n){return M(n).semitones},Sn=function(n){return M(n).chroma},wn=function(n){return "string"==typeof n&&(n=M(n).chroma),"number"==typeof n?pn[n%12]:null},Dn=function(n){void 0===n&&(n={});var t=n.num,r=n.step,e=n.alt,m=n.oct;void 0===m&&(m=1);var i=n.dir;if(void 0!==r&&(t=r+1+7*m),void 0===t)return null;var u=i<0?"-":"",o="PMMPPMM"[On(t)];return u+t+yn(o,e)},En=function(n){var t=M(n);return t===An?null:t.simple+t.q},Cn=function(n){var t=M(n);if(t===An)return null;var r=(7-t.step)%7,e="P"===t.type?-t.alt:-(t.alt+1);return Dn({step:r,alt:e,oct:t.oct,dir:t.dir})},$n=[1,2,2,3,3,4,5,5,6,6,7,7],Fn="P m M m M P d P m M m M".split(" "),Gn=function(n){var t=n<0?-1:1,r=Math.abs(n),e=r%12,m=Math.floor(r/12);return t*($n[e]+7*m)+Fn[e]},In=Object.freeze({names:hn,tokenize:vn,props:M,num:zn,name:qn,semitones:kn,chroma:Sn,ic:wn,build:Dn,simplify:En,invert:Cn,fromSemitones:Gn}),Tn=[0,2,4,-1,1,3,5],Bn=function(n){return Math.floor(7*n/12)},Nn=Tn.map(Bn),Ln=function(n){var t=n.step,r=n.alt,e=n.oct,m=n.dir;void 0===m&&(m=1);var i=Tn[t]+7*r;return null===e?[m*i]:[m*i,m*(e-Nn[t]-4*r)]},Rn=[3,0,4,1,5,2,6],Un=function(n,t,r){var e=Rn[a(n)],m=Math.floor((n+1)/7);return void 0===t?{step:e,alt:m,dir:r}:{step:e,alt:m,oct:t+4*m+Nn[e],dir:r}},Hn=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}},Jn=function(n){return Hn(function(t){var r=n(t);return null===r.name?null:Ln(r)})},Kn=Jn(L),Qn=Jn(M),Vn=function(n){return 7*n[0]+12*n[1]<0},Wn=function(n){return Vn(n)?Un(-n[0],-n[1],-1):Un(n[0],n[1],1)},Xn=Object.freeze({transpose:l,trFifths:c,fifths:s,transposeBy:f,addIntervals:d,add:p,subtract:b,interval:h,semitones:v}),Yn={chromatic:["1P 2m 2M 3m 3M 4P 4A 5P 6m 6M 7m 7M"],lydian:["1P 2M 3M 4A 5P 6M 7M"],major:["1P 2M 3M 4P 5P 6M 7M",["ionian"]],mixolydian:["1P 2M 3M 4P 5P 6M 7m",["dominant"]],dorian:["1P 2M 3m 4P 5P 6M 7m"],aeolian:["1P 2M 3m 4P 5P 6m 7m",["minor"]],phrygian:["1P 2m 3m 4P 5P 6m 7m"],locrian:["1P 2m 3m 4P 5d 6m 7m"],altered:["1P 2m 3m 3M 5d 6m 7m",["super locrian","diminished whole tone","pomeroy"]],iwato:["1P 2m 4P 5d 7m"],hirajoshi:["1P 2M 3m 5P 6m"],kumoijoshi:["1P 2m 4P 5P 6m"],pelog:["1P 2m 3m 5P 6m"],prometheus:["1P 2M 3M 4A 6M 7m"],ritusen:["1P 2M 4P 5P 6M"],scriabin:["1P 2m 3M 5P 6M"],piongio:["1P 2M 4P 5P 6M 7m"],augmented:["1P 2A 3M 5P 5A 7M"],neopolitan:["1P 2m 3m 4P 5P 6m 7M"],diminished:["1P 2M 3m 4P 5d 6m 6M 7M"],egyptian:["1P 2M 4P 5P 7m"],oriental:["1P 2m 3M 4P 5d 6M 7m"],spanish:["1P 2m 3M 4P 5P 6m 7m",["phrygian major"]],flamenco:["1P 2m 3m 3M 4A 5P 7m"],balinese:["1P 2m 3m 4P 5P 6m 7M"],persian:["1P 2m 3M 4P 5d 6m 7M"],bebop:["1P 2M 3M 4P 5P 6M 7m 7M"],enigmatic:["1P 2m 3M 5d 6m 7m 7M"],ichikosucho:["1P 2M 3M 4P 5d 5P 6M 7M"],"melodic minor":["1P 2M 3m 4P 5P 6M 7M"],"melodic minor second mode":["1P 2m 3m 4P 5P 6M 7m"],"lydian augmented":["1P 2M 3M 4A 5A 6M 7M"],"lydian dominant":["1P 2M 3M 4A 5P 6M 7m",["lydian b7"]],"melodic minor fifth mode":["1P 2M 3M 4P 5P 6m 7m",["hindu","mixolydian b6M"]],"locrian #2":["1P 2M 3m 4P 5d 6m 7m"],"locrian major":["1P 2M 3M 4P 5d 6m 7m",["arabian"]],"major pentatonic":["1P 2M 3M 5P 6M",["pentatonic"]],"lydian pentatonic":["1P 3M 4A 5P 7M",["chinese"]],"mixolydian pentatonic":["1P 3M 4P 5P 7m",["indian"]],"locrian pentatonic":["1P 3m 4P 5d 7m",["minor seven flat five pentatonic"]],"minor pentatonic":["1P 3m 4P 5P 7m"],"minor six pentatonic":["1P 3m 4P 5P 6M"],"minor hexatonic":["1P 2M 3m 4P 5P 7M"],"flat three pentatonic":["1P 2M 3m 5P 6M",["kumoi"]],"flat six pentatonic":["1P 2M 3M 5P 6m"],"major flat two pentatonic":["1P 2m 3M 5P 6M"],"whole tone pentatonic":["1P 3M 5d 6m 7m"],"ionian pentatonic":["1P 3M 4P 5P 7M"],"lydian #5P pentatonic":["1P 3M 4A 5A 7M"],"lydian dominant pentatonic":["1P 3M 4A 5P 7m"],"minor #7M pentatonic":["1P 3m 4P 5P 7M"],"super locrian pentatonic":["1P 3m 4d 5d 7m"],"in-sen":["1P 2m 4P 5P 7m"],"vietnamese 1":["1P 3m 4P 5P 6m"],"vietnamese 2":["1P 3m 4P 5P 7m"],"prometheus neopolitan":["1P 2m 3M 4A 6M 7m"],"major blues":["1P 2M 3m 3M 5P 6M"],"minor blues":["1P 3m 4P 5d 5P 7m",["blues"]],"composite blues":["1P 2M 3m 3M 4P 5d 5P 6M 7m"],"augmented heptatonic":["1P 2A 3M 4P 5P 5A 7M"],"dorian #4":["1P 2M 3m 4A 5P 6M 7m"],"lydian diminished":["1P 2M 3m 4A 5P 6M 7M"],"whole tone":["1P 2M 3M 4A 5A 7m"],"leading whole tone":["1P 2M 3M 4A 5A 7m 7M"],"harmonic minor":["1P 2M 3m 4P 5P 6m 7M"],"lydian minor":["1P 2M 3M 4A 5P 6m 7m"],"neopolitan minor":["1P 2m 3m 4P 5P 6m 7M"],"neopolitan major":["1P 2m 3m 4P 5P 6M 7M",["dorian b2"]],"neopolitan major pentatonic":["1P 3M 4P 5d 7m"],"romanian minor":["1P 2M 3m 5d 5P 6M 7m"],"double harmonic lydian":["1P 2m 3M 4A 5P 6m 7M"],"harmonic major":["1P 2M 3M 4P 5P 6m 7M"],"double harmonic major":["1P 2m 3M 4P 5P 6m 7M",["gypsy"]],"hungarian minor":["1P 2M 3m 4A 5P 6m 7M"],"hungarian major":["1P 2A 3M 4A 5P 6M 7m"],"spanish heptatonic":["1P 2m 3m 3M 4P 5P 6m 7m"],"todi raga":["1P 2m 3m 4A 5P 6m 7M"],"malkos raga":["1P 3m 4P 6m 7m"],"kafi raga":["1P 3m 3M 4P 5P 6M 7m 7M"],"purvi raga":["1P 2m 3M 4P 4A 5P 6m 7M"],"bebop dominant":["1P 2M 3M 4P 5P 6M 7m 7M"],"bebop minor":["1P 2M 3m 3M 4P 5P 6M 7m"],"bebop major":["1P 2M 3M 4P 5P 5A 6M 7M"],"bebop locrian":["1P 2m 3m 4P 5d 5P 6m 7m"],"minor bebop":["1P 2M 3m 4P 5P 6m 7m 7M"],"mystery #1":["1P 2m 3M 5d 6m 7m"],"minor six diminished":["1P 2M 3m 4P 5P 6m 6M 7M"],"ionian augmented":["1P 2M 3M 4P 5A 6M 7M"],"lydian #9":["1P 2m 3M 4A 5P 6M 7M"],"six tone symmetric":["1P 2m 3M 4P 5A 6M"]},Zn={M:["1P 3M 5P",["Major",""]],M13:["1P 3M 5P 7M 9M 13M",["maj13","Maj13"]],M6:["1P 3M 5P 13M",["6"]],M69:["1P 3M 5P 6M 9M",["69"]],M7add13:["1P 3M 5P 6M 7M 9M"],M7b5:["1P 3M 5d 7M"],M7b6:["1P 3M 6m 7M"],M7b9:["1P 3M 5P 7M 9m"],M7sus4:["1P 4P 5P 7M"],M9:["1P 3M 5P 7M 9M",["maj9","Maj9"]],M9b5:["1P 3M 5d 7M 9M"],M9sus4:["1P 4P 5P 7M 9M"],Madd9:["1P 3M 5P 9M",["2","add9","add2"]],Maj7:["1P 3M 5P 7M",["maj7","M7"]],Mb5:["1P 3M 5d"],Mb6:["1P 3M 13m"],Msus2:["1P 2M 5P",["add9no3","sus2"]],Msus4:["1P 4P 5P",["sus","sus4"]],Maddb9:["1P 3M 5P 9m"],m:["1P 3m 5P"],m11:["1P 3m 5P 7m 9M 11P",["_11"]],m11b5:["1P 3m 7m 12d 2M 4P",["h11","_11b5"]],m13:["1P 3m 5P 7m 9M 11P 13M",["_13"]],m6:["1P 3m 4P 5P 13M",["_6"]],m69:["1P 3m 5P 6M 9M",["_69"]],m7:["1P 3m 5P 7m",["minor7","_","_7"]],m7add11:["1P 3m 5P 7m 11P",["m7add4"]],m7b5:["1P 3m 5d 7m",["half-diminished","h7","_7b5"]],m9:["1P 3m 5P 7m 9M",["_9"]],m9b5:["1P 3m 7m 12d 2M",["h9","-9b5"]],mMaj7:["1P 3m 5P 7M",["mM7","_M7"]],mMaj7b6:["1P 3m 5P 6m 7M",["mM7b6"]],mM9:["1P 3m 5P 7M 9M",["mMaj9","-M9"]],mM9b6:["1P 3m 5P 6m 7M 9M",["mMaj9b6"]],mb6M7:["1P 3m 6m 7M"],mb6b9:["1P 3m 6m 9m"],o:["1P 3m 5d",["mb5","dim"]],o7:["1P 3m 5d 13M",["diminished","m6b5","dim7"]],o7M7:["1P 3m 5d 6M 7M"],oM7:["1P 3m 5d 7M"],sus24:["1P 2M 4P 5P",["sus4add9"]],madd4:["1P 3m 4P 5P"],madd9:["1P 3m 5P 9M"],4:["1P 4P 7m 10m",["quartal"]],5:["1P 5P"],7:["1P 3M 5P 7m",["Dominant","Dom"]],9:["1P 3M 5P 7m 9M",["79"]],11:["1P 5P 7m 9M 11P"],13:["1P 3M 5P 7m 9M 13M",["13_"]],64:["5P 8P 10M"],"M#5":["1P 3M 5A",["augmented","maj#5","Maj#5","+","aug"]],"M#5add9":["1P 3M 5A 9M",["+add9"]],"M13#11":["1P 3M 5P 7M 9M 11A 13M",["maj13#11","Maj13#11","M13+4","M13#4"]],"M6#11":["1P 3M 5P 6M 11A",["M6b5","6#11","6b5"]],"M69#11":["1P 3M 5P 6M 9M 11A"],"M7#11":["1P 3M 5P 7M 11A",["maj7#11","Maj7#11","M7+4","M7#4"]],"M7#5":["1P 3M 5A 7M",["maj7#5","Maj7#5","maj9#5","M7+"]],"M7#5sus4":["1P 4P 5A 7M"],"M7#9#11":["1P 3M 5P 7M 9A 11A"],"M9#11":["1P 3M 5P 7M 9M 11A",["maj9#11","Maj9#11","M9+4","M9#4"]],"M9#5":["1P 3M 5A 7M 9M",["Maj9#5"]],"M9#5sus4":["1P 4P 5A 7M 9M"],"11b9":["1P 5P 7m 9m 11P"],"13#11":["1P 3M 5P 7m 9M 11A 13M",["13+4","13#4"]],"13#9":["1P 3M 5P 7m 9A 13M",["13#9_"]],"13#9#11":["1P 3M 5P 7m 9A 11A 13M"],"13b5":["1P 3M 5d 6M 7m 9M"],"13b9":["1P 3M 5P 7m 9m 13M"],"13b9#11":["1P 3M 5P 7m 9m 11A 13M"],"13no5":["1P 3M 7m 9M 13M"],"13sus4":["1P 4P 5P 7m 9M 13M",["13sus"]],"69#11":["1P 3M 5P 6M 9M 11A"],"7#11":["1P 3M 5P 7m 11A",["7+4","7#4","7#11_","7#4_"]],"7#11b13":["1P 3M 5P 7m 11A 13m",["7b5b13"]],"7#5":["1P 3M 5A 7m",["+7","7aug","aug7"]],"7#5#9":["1P 3M 5A 7m 9A",["7alt","7#5#9_","7#9b13_"]],"7#5b9":["1P 3M 5A 7m 9m"],"7#5b9#11":["1P 3M 5A 7m 9m 11A"],"7#5sus4":["1P 4P 5A 7m"],"7#9":["1P 3M 5P 7m 9A",["7#9_"]],"7#9#11":["1P 3M 5P 7m 9A 11A",["7b5#9"]],"7#9#11b13":["1P 3M 5P 7m 9A 11A 13m"],"7#9b13":["1P 3M 5P 7m 9A 13m"],"7add6":["1P 3M 5P 7m 13M",["67","7add13"]],"7b13":["1P 3M 7m 13m"],"7b5":["1P 3M 5d 7m"],"7b6":["1P 3M 5P 6m 7m"],"7b9":["1P 3M 5P 7m 9m"],"7b9#11":["1P 3M 5P 7m 9m 11A",["7b5b9"]],"7b9#9":["1P 3M 5P 7m 9m 9A"],"7b9b13":["1P 3M 5P 7m 9m 13m"],"7b9b13#11":["1P 3M 5P 7m 9m 11A 13m",["7b9#11b13","7b5b9b13"]],"7no5":["1P 3M 7m"],"7sus4":["1P 4P 5P 7m",["7sus"]],"7sus4b9":["1P 4P 5P 7m 9m",["susb9","7susb9","7b9sus","7b9sus4","phryg"]],"7sus4b9b13":["1P 4P 5P 7m 9m 13m",["7b9b13sus4"]],"9#11":["1P 3M 5P 7m 9M 11A",["9+4","9#4","9#11_","9#4_"]],"9#11b13":["1P 3M 5P 7m 9M 11A 13m",["9b5b13"]],"9#5":["1P 3M 5A 7m 9M",["9+"]],"9#5#11":["1P 3M 5A 7m 9M 11A"],"9b13":["1P 3M 7m 9M 13m"],"9b5":["1P 3M 5d 7m 9M"],"9no5":["1P 3M 7m 9M"],"9sus4":["1P 4P 5P 7m 9M",["9sus"]],"m#5":["1P 3m 5A",["m+","mb6"]],"m11A 5":["1P 3m 6m 7m 9M 11P"],"m7#5":["1P 3m 6m 7m"],"m9#5":["1P 3m 6m 7m 9M"],"+add#9":["1P 3M 5A 9A"]},nt=function(n){return X(n)||Sn(n)||0},tt=function(n){return parseInt(A(n),2)},rt=function(n){return n.replace(/0/g,"").length},et=null,mt=/^[01]{12}$/,it="1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M".split(" "),ut=Object.freeze({chroma:A,chromas:g,modes:j,isChroma:y,intervals:O,isEqual:x,isSubsetOf:_,isSupersetOf:z,includes:q,filter:k}),ot=function(n){var t=Object.keys(n).sort(),r=[],e=[],m=function(n,t,m){r[n]=t,e[m]=e[m]||[],e[m].push(n);};t.forEach(function(t){var r=n[t][0].split(" "),e=n[t][1],i=A(r);m(t,r,i),e&&e.forEach(function(n){return m(n,r,i)});});var i=Object.keys(r).sort(),u=function(n){return r[n]};return u.names=function(n){return "string"==typeof n?(e[n]||[]).slice():(!0===n?i:t).slice()},u},Pt=function(n,t){var r=function(r){return n(r)||t(r)};return r.names=function(r){return n.names(r).concat(t.names(r))},r},Mt=ot(Yn),at=ot(Zn),lt=Pt(Mt,at),ct=Object.freeze({dictionary:ot,combine:Pt,scale:Mt,chord:at,pcset:lt}),st=Object.freeze({name:null,intervals:[],names:[],chroma:null,setnum:null}),ft=function(n,t){return function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=Mt(n);if(!t)return st;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=Mt.names(r.chroma),Object.freeze(r)},{}),dt=Mt.names,pt=function(n){var t=D(n);return ft(t[1]).intervals},bt=function(n){var t=pt(n),r=S(n);return j(t).map(function(n,e){var m=Mt.names(n)[0];if(m)return [r[e]||t[e],m]}).filter(function(n){return n})},ht=function(n){var t=_(pt(n));return at.names().filter(function(n){return t(at(n))})},vt=function(n){var t=Mn(n.map(U));if(!t.length)return t;var r=t[0],e=P(t);return u(e.indexOf(r),e)},At=function(n){if(!pt(n).length)return [];var t=z(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},gt=function(n){var t=_(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},jt=Object.freeze({props:ft,names:dt,intervals:pt,notes:S,exists:w,tokenize:D,modeNames:bt,chords:ht,toScale:vt,supersets:At,subsets:gt}),yt=at.names,Ot=Object.freeze({name:null,names:[],intervals:[],chroma:null,setnum:null}),xt=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=at(n);if(!t)return Ot;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=at.names(r.chroma),r}),_t=function(n){return xt(C(n)[1]).intervals},zt=function(n){return void 0!==at(C(n)[1])},qt=function(n){if(!_t(n).length)return [];var t=z(_t(n));return at.names().filter(function(n){return t(at(n))})},kt=function(n){var t=_(_t(n));return at.names().filter(function(n){return t(at(n))})},St=/^(6|64|7|9|11|13)$/,wt=Object.freeze({names:yt,props:xt,intervals:_t,notes:E,exists:zt,supersets:qt,subsets:kt,tokenize:C}),Dt=l,Et=h,Ct=L,$t=H,Ft=K,Gt=at,It=Mt;n.Array=sn,n.Note=Pn,n.Interval=In,n.Distance=Xn,n.Scale=jt,n.Chord=wt,n.PcSet=ut,n.Dictionary=ct,n.transpose=Dt,n.interval=Et,n.note=Ct,n.midi=$t,n.freq=Ft,n.chord=Gt,n.scale=It,Object.defineProperty(n,"__esModule",{value:!0});})(tonal$1); -//import {Nil} from './type_utils.js'; -class MelodicBeatLiteral { - constructor(opts) { - this.time = opts.time || { time: 'auto' }; - this.pitch = opts.pitch; - this.octave = opts.octave || 'inherit'; - this.scope = null; - this.parentMeasure = null; - this.indexInMeasure = null; - this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation - } - init(scope, parentMeasure, indexInMeasure) { - this.scope = scope; - this.parentMeasure = parentMeasure; - this.indexInMeasure = indexInMeasure; - } - getTime() { - if (this.time.time === 'auto') { - return this.indexInMeasure + 1; - } - else { - return this.time.time; - } - } - /** - * Normalize a chord into a form tonal can handle - * @param {string} [chord=''] - * @return {string} - */ - static normalizeChord(chord = '') { - return chord - .replace(/-/g, '_') // tonal uses _ over - for minor7 - .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? - } - static chordToScaleName(chord) { - let chordType = tonal$1.Chord.tokenize(chord)[1]; - // @TODO: make this more robust - let names = tonal$1.Chord.props(chordType).names; - if (names.includes('dim')) - return 'diminished'; - if (names.includes('aug')) - return 'augmented'; - if (names.includes('Major')) - return 'major'; - if (names.includes('minor')) - return 'minor'; - if (names.includes('minor7')) - return 'dorian'; - if (names.includes('Dominant')) - return 'mixolydian'; - // if none of the above match, do our best to find the closest fit - let closestScale = 'major'; - names.forEach(name => { - if (name.startsWith('dim')) - closestScale = 'diminished'; - if (name.startsWith('aug')) - closestScale = 'augmented'; - if (name.startsWith('M')) - closestScale = 'major'; - if (name.startsWith('m')) - closestScale = 'minor'; - }); - return closestScale; - } - handleInversion(songIterator, pitches) { - let tonicPC = songIterator.song.getTransposedKey(); - let tonicNote = tonal$1.Note.from({ oct: this.getOctave() }, tonicPC); - let tonic = tonal$1.Note.midi(tonicNote); - let outPitches = []; - for (let pitchNote of pitches) { - let pitch = tonal$1.Note.midi(pitchNote); - if (pitch - tonic >= 6) - pitch -= 12; - outPitches.push(tonal$1.Note.fromMidi(pitch)); - } - return outPitches; - } - static getAnchorChord(anchor, songIterator, currentTime) { - let anchorChord; - switch (anchor) { - case 'KEY': { - anchorChord = songIterator.song.getTransposedKey(); - } - case 'NEXT': { - let nextMeasure = songIterator.getRelative(1); - if (nextMeasure) { - anchorChord = nextMeasure.beats[0].chord; - } - else { - anchorChord = songIterator.song.getTransposedKey(); - } +function normalizeChordForTonal(chord = '') { + return chord + .replace(/-/g, '_') // tonal uses _ over - for minor7 + .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? +} +function getAnchorChord(anchor, songIterator, currentTime) { + let anchorChord; + switch (anchor) { + case 'KEY': { + anchorChord = songIterator.song.getTransposedKey(); + } + case 'NEXT': { + let nextMeasure = songIterator.getRelative(1); + if (nextMeasure) { + anchorChord = nextMeasure.beats[0].chord; } - case 'STEP': - case 'ARPEGGIATE': - default: { - // crawl backward through this measure to get the last set beat - let lastSetBeat = Math.floor(currentTime); - let iteratorMeasure = songIterator.getRelative(0); - if (!iteratorMeasure) - break; - do { - const beat = iteratorMeasure.beats[lastSetBeat]; - anchorChord = beat && beat.chord; - lastSetBeat--; - } while (!anchorChord); + else { + anchorChord = songIterator.song.getTransposedKey(); } } - return this.normalizeChord(anchorChord); - } - static anchorChordToRoot(anchorChord, degree, octave) { - let anchorTonic = tonal$1.Chord.tokenize(anchorChord)[0]; - let anchorScaleName = this.chordToScaleName(anchorChord); - let scalePCs = tonal$1.Scale.notes(anchorTonic, anchorScaleName); - let rootPC = scalePCs[degree - 1]; - return tonal$1.Note.from({ oct: octave }, rootPC); - } - getAnchorData(songIterator) { - let anchorChord = MelodicBeatLiteral.getAnchorChord(this.pitch.anchor, songIterator, this.getTime()); - let root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, this.pitch.degree, this.getOctave()); - return [anchorChord, root]; - } - getPitches(songIterator) { - let [anchorChord, root] = this.getAnchorData(songIterator); - let pitches; - if (this.pitch.chord) { - // this feels extremely incorrect - // why would anyone need it to work this way - let anchorChordType = tonal$1.Chord.tokenize(anchorChord)[1]; - pitches = tonal$1.Chord.notes(root, anchorChordType); - } - else { - pitches = [root]; - } - if (this.scope.vars.get('invertible')) { - pitches = this.handleInversion(songIterator, pitches); - } - return pitches; - } - /** - * Returns true if the beat is anchored via STEP or ARPEGGIATE - * @returns {boolean} - */ - isDynamic() { - return ['STEP', 'ARPEGGIATE'].includes(this.pitch.anchor); - } - getOctave() { - if (this.octave === 'inherit') { - return this.scope.vars.get('octave'); - } - else { - return this.octave; - } + case 'STEP': + case 'ARPEGGIATE': + default: { + // crawl backward through this measure to get the last set beat + let lastSetBeat = Math.floor(currentTime); + let iteratorMeasure = songIterator.getRelative(0); + if (!iteratorMeasure) + break; + do { + const beat = iteratorMeasure.beats[lastSetBeat]; + anchorChord = beat && beat.chord; + lastSetBeat--; + } while (!anchorChord); + } + } + return normalizeChordForTonal(anchorChord); +} +function anchorChordToRoot(anchorChord, degree, octave) { + let anchorTonic = tonal$1.Chord.tokenize(anchorChord)[0]; + let anchorScaleName = chordToScaleName(anchorChord); + let scalePCs = tonal$1.Scale.notes(anchorTonic, anchorScaleName); + let rootPC = scalePCs[degree - 1]; + return tonal$1.Note.from({ oct: octave }, rootPC); +} +function chordToScaleName(chord) { + let chordType = tonal$1.Chord.tokenize(chord)[1]; + // @TODO: make this more robust + let names = tonal$1.Chord.props(chordType).names; + if (names.includes('dim')) + return 'diminished'; + if (names.includes('aug')) + return 'augmented'; + if (names.includes('Major')) + return 'major'; + if (names.includes('minor')) + return 'minor'; + if (names.includes('minor7')) + return 'dorian'; + if (names.includes('Dominant')) + return 'mixolydian'; + // if none of the above match, do our best to find the closest fit + let closestScale = 'major'; + names.forEach(name => { + if (name.startsWith('dim')) + closestScale = 'diminished'; + if (name.startsWith('aug')) + closestScale = 'augmented'; + if (name.startsWith('M')) + closestScale = 'major'; + if (name.startsWith('m')) + closestScale = 'minor'; + }); + return closestScale; +} + +const anchorReverseMap = { 'KEY': 'k', 'NEXT': 'n', 'STEP': 's', 'ARPEGGIATE': 'a' }; +class PlaybackAnchorValue { + constructor(value) { + this.type = 'anchor'; + this.value = value; } - getDuration() { - let duration; - duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); - if (this.time.flag === 'STACCATO') { - return Math.min(0.25, duration); - } - else { - return duration; - } + toBoolean() { return true; } + toOutputString() { return anchorReverseMap[this.value]; } +} +class PlaybackBeatValue { + constructor() { + this.type = null; } - getVolume() { - let volume = this.scope.vars.get('volume'); - if (this.time.flag === 'ACCENTED') - volume = Math.min(1, volume += .1); - return volume; + toBoolean() { return true; } +} +class PlaybackMelodicBeatValue extends PlaybackBeatValue { + constructor(time = { time: 'auto' }, pitch, octave = 'inherit') { + super(); + this.type = 'melodic_beat'; + this.value = { + time: null, + pitch: null, + octave: null, + }; + this.value.time = time; + this.value.pitch = pitch; + this.value.octave = octave; + } + toOutputString() { + const timeFlag = this.time.flag ? (this.time.flag === 'ACCENTED' ? 'a' : 's') : ''; + const timePart = `${this.time.time === 'auto' ? '' : this.time.time}${timeFlag}`; + const pitchAnchor = this.pitch.anchor ? anchorReverseMap[this.pitch.anchor] : ''; + const pitchRoll = this.pitch.roll ? (this.pitch.roll === 'ROLL_UP' ? 'r' : 'rd') : ''; + const pitchPart = `:${pitchAnchor}${this.pitch.degree || ''}${this.pitch.chord ? 'c' : ''}${pitchRoll}`; + const octavePart = this.octave === 'inherit' ? '' : `:${this.octave}`; + return `${timePart}${pitchPart}${octavePart}`; + } + get time() { return this.value.time; } + get pitch() { return this.value.pitch; } + get octave() { return this.value.octave; } +} +class PlaybackDrumBeatValue extends PlaybackBeatValue { + constructor(time, accented = false) { + super(); + this.type = 'drum_beat'; + this.value = { + time: null, + accented: null, + }; + this.value.time = time; + this.value.accented = accented; } - execute(songIterator) { - let notes = new NoteSet(); - let time = this.getTime(); // @TODO: this varies with rolling - let pitches = this.getPitches(songIterator); - let duration = this.getDuration(); // @TODO: this varies with rolling - let volume = this.getVolume(); - for (let pitch of pitches) { - notes.push(new Note({ - time: time, - pitch: pitch, - duration: duration, - volume: volume - })); - } - return notes; + toOutputString() { + return `${this.time}${this.accented ? 'a' : ''}`; } + get time() { return this.value.time; } + get accented() { return this.value.accented; } } -class DrumBeatLiteral { - constructor(opts) { - this.time = opts.time; - this.accented = opts.accented || false; - this.scope = null; - this.parentMeasure = null; - this.indexInMeasure = null; - } - init(scope, parentMeasure, indexInMeasure) { - this.scope = scope; - this.parentMeasure = parentMeasure; - this.indexInMeasure = indexInMeasure; + +class PlaybackNilValue { + constructor() { + this.type = 'Nil'; + this.value = null; } - getTime() { - return this.time; + toBoolean() { return false; } + toOutputString() { return 'Nil'; } +} +class PlaybackStringValue { + constructor(value) { + this.type = 'string'; + this.value = value; } - getDuration() { - let duration; - duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); - return duration; + toBoolean() { return this.value !== ''; } + toOutputString() { + // @TODO: store raw value from tokenizer? (which may not always exist for programmatically-generated strings) + // At least this is consistent... + return `"${this.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`; } - getVolume() { - let volume = this.scope.vars.get('volume'); - if (this.accented) - volume = Math.min(1, volume += .1); - return volume; +} +class PlaybackNumberValue { + constructor(value) { + this.type = 'number'; + this.value = value; + } + toInteger() { return Math.floor(this.value); } + toBoolean() { return this.value !== 0; } + toOutputString() { return this.value.toString(); } +} +class PlaybackBooleanValue { + constructor(value) { + this.type = 'boolean'; + this.value = value; } - execute(songIterator) { - let time = this.getTime(); - let duration = this.getDuration(); - let volume = this.getVolume(); - return new NoteSet(new Note({ - time: time, - pitch: AwaitingDrum, - duration: duration, - volume: volume - })); + toBoolean() { return this.value; } + toOutputString() { return this.value ? 'true' : 'false'; } +} +class PlaybackTimeSignatureValue { + constructor(value) { + this.type = 'time_signature'; + this.value = value; } + toBoolean() { return true; } + toOutputString() { return `${this.value[0]} / ${this.value[1]}`; } } let definitions = new Map(); @@ -1481,38 +1425,25 @@ function assertArgTypes(identifier, args, types, scope) { if (types == '*') return; if (args.length != types.length) { - throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, scope); + throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, args, scope); } for (let i in args) { if (types[i] == '*') continue; let arg = args[i]; if (arg instanceof FunctionCall) { - arg = arg.returns; - if (arg == '*') { + if (arg.returns == '*') { continue; // what's the correct functionality here? cry? } - else if (typeof types[i] == 'string') { - if (arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); - } - } else { - if (arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); + if (arg.returns !== types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, args, scope); } } } else { - if (typeof types[i] == 'string') { - if (typeof arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); - } - } - else { - if (!(arg instanceof types[i])) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); - } + if (arg.type !== types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, args, scope); } } } @@ -1585,7 +1516,7 @@ let define$1 = function (identifier, opts, func) { scope: opts.scope || 'no-meta', execute: (args, songIterator, scope) => { let argErr = message => { - throw new FunctionArgumentsError(message, scope); + throw new FunctionArgumentsError(message, args, scope); }; return func(args, songIterator, scope, argErr); } @@ -1605,11 +1536,11 @@ let defineVar = function (identifier, type, goalscope = null) { let opts = { types: [type], scope: goalscope, - returns: Nil + returns: 'Nil' }; define$1(identifier, opts, (args, songIterator, scope, argErr) => { scope.vars.set(identifier, args[0]); - return Nil; + return new PlaybackNilValue(); }); }; /** @@ -1623,8 +1554,8 @@ let defineVar = function (identifier, type, goalscope = null) { let defineBoolean = function (identifier, goalscope = null) { let opts = { types: '*', - scopes: goalscope, - returns: Nil + scope: goalscope, + returns: 'Nil' }; define$1(identifier, opts, (args, songIterator, scope, argErr) => { if (args.length) { @@ -1632,9 +1563,9 @@ let defineBoolean = function (identifier, goalscope = null) { scope.vars.set(identifier, args[0]); } else { - scope.vars.set(identifier, true); + scope.vars.set(identifier, new PlaybackBooleanValue(true)); } - return Nil; + return new PlaybackNilValue; }); }; /*********** ACTUAL FUNCTION DEFINITIONS ***********/ @@ -1647,38 +1578,42 @@ defineVar('playback-version', 'number', 'meta'); define$1('time-signature', { types: ['number', 'number'], scope: 'options', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (!Number.isInteger(Math.log2(args[1]))) { - argErr(`Argument 2 of "time-signature" must be a power of 2 (got ${args}).`); + const value1 = args[0].value; + const value2 = args[1].value; + if (!Number.isInteger(Math.log2(value1))) { + argErr(`Argument 2 of "time-signature" must be a power of 2`); } - scope.vars.set('time-signature', [args[0], args[1]]); - return Nil; + scope.vars.set('time-signature', new PlaybackTimeSignatureValue([value1, value2])); + return new PlaybackNilValue(); }); defineBoolean('swing', 'options'); /*** anywhere but @meta functions ***/ define$1('volume', { types: ['number'], scope: 'no-meta', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (args[0] < 0 || args[0] > 1) { - argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive) (got ${args}).`); + const { value } = args[0]; + if (value < 0 || value > 1) { + argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive)`); } scope.vars.set('volume', args[0]); - return Nil; + return new PlaybackNilValue(); }); defineBoolean('invertible', 'no-meta'); define$1('octave', { types: ['number'], scope: 'no-meta', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { - argErr(`Argument 1 of "octave" must be an integer 0-9 (got ${args}).`); + const { value } = args[0]; + if (!Number.isInteger(value) || value < 0 || value > 9) { + argErr(`Argument 1 of "octave" must be an integer 0-9`); } scope.vars.set('octave', args[0]); - return Nil; + return new PlaybackNilValue(); }); /*** anywhere but config functions (strictly dynamic functions) ***/ define$1('choose', { @@ -1686,24 +1621,24 @@ define$1('choose', { scope: 'no-config', returns: '*' }, (args, songIterator, scope, argErr) => { - let nonNilArgs = args.filter(arg => arg !== Nil); + let nonNilArgs = args.filter(arg => arg.type !== 'Nil'); if (nonNilArgs.length) { let index = Math.floor(Math.random() * nonNilArgs.length); return nonNilArgs[index]; } else { - return Nil; + return new PlaybackNilValue(); } }); let anchorOrNumberToChordAndRoot = function (arg, songIterator) { let anchorChord, root; - if (typeof arg == 'number') { - anchorChord = MelodicBeatLiteral.getAnchorChord(null, songIterator, 1); - root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, arg, 4); + if (arg.type === 'number') { + anchorChord = getAnchorChord(null, songIterator, 1); + root = anchorChordToRoot(anchorChord, arg.value, 4); } - else if (arg.anchor) { - anchorChord = MelodicBeatLiteral.getAnchorChord(arg.anchor, songIterator, 1); - root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, 1, 4); + else { + anchorChord = getAnchorChord(arg.value, songIterator, 1); + root = anchorChordToRoot(anchorChord, 1, 4); } return [anchorChord, root]; }; @@ -1713,34 +1648,34 @@ define$1('progression', { returns: 'boolean' }, (args, songIterator, scope, argErr) => { for (let i in args) { - let arg = args[i]; - let [, goal] = anchorOrNumberToChordAndRoot(arg, songIterator); - if (!goal) { - argErr(`Arguments of "progression" must be numbers or anchors (got "${args}").`); + if (args[0].type !== 'number' && args[0].type !== 'anchor') { + argErr(`Arguments of "progression" must be numbers or anchors`); } - let actualMeasure = songIterator.getRelative(Number(i)); + const [, goal] = anchorOrNumberToChordAndRoot(args[0], songIterator); + const actualMeasure = songIterator.getRelative(Number(i)); if (!actualMeasure) - return false; - let actualChord = MelodicBeatLiteral.normalizeChord(actualMeasure.beats[0].chord); - let actual = MelodicBeatLiteral.anchorChordToRoot(actualChord, 1, 4); + return new PlaybackBooleanValue(false); + const actualChord = normalizeChordForTonal(actualMeasure.beats[0].chord); + const actual = anchorChordToRoot(actualChord, 1, 4); if (actual != goal) - return false; + return new PlaybackBooleanValue(false); } - return true; + return new PlaybackBooleanValue(true); }); define$1('in-scale', { types: '*', scope: 'no-config', returns: 'boolean' }, (args, songIterator, scope, argErr) => { + if ((args[0].type !== 'number' && args[0].type !== 'anchor') + || args[1].type !== 'number' && args[1].type !== 'anchor') { + argErr(`Arguments of "in-scale" must be numbers or anchors`); + } let [, note] = anchorOrNumberToChordAndRoot(args[0], songIterator); let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); - if (!note || !goalChord) { - argErr(`Arguments of "in-scale" must be numbers or anchors (got ${args}).`); - } - let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); + let goalScaleName = chordToScaleName(goalChord); let goalScale = tonal$1.Scale.notes(goalTonic, goalScaleName); - return goalScale.includes(note); + return new PlaybackBooleanValue(goalScale.includes(note)); }); define$1('beat-defined', { types: ['number'], @@ -1749,8 +1684,9 @@ define$1('beat-defined', { }, (args, songIterator, scope, argErr) => { let measure = songIterator.getRelative(0); if (!measure) - return false; - return measure.beats[args[0]].chord !== null; + return new PlaybackBooleanValue(false); + const index = args[0].value; + return new PlaybackBooleanValue(measure.beats[index].chord !== null); }); /*** pattern-only functions ***/ defineBoolean('private', 'pattern'); @@ -1758,13 +1694,13 @@ defineVar('length', 'number', 'pattern'); define$1('chance', { types: ['number'], scope: 'pattern', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (args[0] < 0 || args[0] > 1) { - argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive) (got ${args}).`); + if (args[0].value < 0 || args[0].value > 1) { + argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive)`); } scope.vars.set('chance', args[0]); - return Nil; + return new PlaybackNilValue(); }); /** @@ -1827,8 +1763,8 @@ class PatternExpressionGroup extends Scope { super(); this.type = 'PatternExpressionGroup'; this.name = '@pattern()'; - this.defaultVars.set('private', false); - this.defaultVars.set('chance', 1); + this.defaultVars.set('private', new PlaybackBooleanValue(false)); + this.defaultVars.set('chance', new PlaybackNumberValue(1)); this.expressions = expressions; this.functionCalls = []; this.nonFunctionCallExpressions = []; @@ -1861,25 +1797,25 @@ class PatternExpressionGroup extends Scope { } execute(songIterator, callerIsTrack = false) { this.inherit(); - let beats = Nil; + let beats = null; for (let function_call of this.functionCalls) { let return_value = function_call.execute(songIterator); if (return_value instanceof NoteSet) { - if (beats !== Nil) { + if (beats) { throw new TooManyBeatsError(this); } beats = return_value; } } - if (callerIsTrack && this.vars.get('private') === true) { - return Nil; // if it's private we can give up now + if (callerIsTrack && this.vars.get('private').value === true) { + return null; // if it's private we can give up now } for (let expression of this.nonFunctionCallExpressions) { if (expression.execute) { expression = expression.execute(songIterator); } if (expression instanceof NoteSet) { - if (beats !== Nil) { + if (beats) { throw new TooManyBeatsError(this); } beats = expression; @@ -1901,7 +1837,7 @@ class PatternStatement extends PatternExpressionGroup { this.condition = (opts.condition !== undefined) ? opts.condition : null; } getChance() { - return this.vars.get('chance'); + return this.vars.get('chance').value; } link(ASTs, parentStyle, parentTrack) { super.link(ASTs, parentStyle, parentTrack); @@ -1923,8 +1859,8 @@ class PatternStatement extends PatternExpressionGroup { else { condition_value = this.condition; } - if (cast_bool(condition_value) === false) - return Nil; + if (condition_value.toBoolean() === false) + return null; } return super.execute(songIterator, callerIsTrack); } @@ -1941,7 +1877,7 @@ class PatternCall { this.pattern; } getChance() { - return this.patternStatement.getChance()(); + return this.patternStatement.getChance(); } init(scope) { this.scope = scope; @@ -2007,7 +1943,7 @@ class JoinedPatternExpression { return (new NoteSet()).concat(...noteSets); } else { - return Nil; + return null; } } } @@ -2017,9 +1953,9 @@ class TrackStatement extends Scope { super(); this.name = opts.identifier; this.type = '@track'; - this.defaultVars.set('octave', 4); - this.defaultVars.set('volume', 1); - this.defaultVars.set('private', false); + this.defaultVars.set('octave', new PlaybackNumberValue(4)); + this.defaultVars.set('volume', new PlaybackNumberValue(1)); + this.defaultVars.set('private', new PlaybackBooleanValue(false)); this.instrument = opts.instrument; this.identifier = opts.identifier; this.members = opts.members; @@ -2069,7 +2005,7 @@ class TrackStatement extends Scope { let result = pattern.execute(songIterator, true); console.log(' - Result:', result); // @TODO: handle multi-measure patterns (via locks?) - if (result !== Nil) { + if (result) { for (let note of result) { if (note.pitch === AwaitingDrum) { throw new DrumBeatInMelodicBeatGroupError(pattern); @@ -2092,8 +2028,8 @@ class TrackStatement extends Scope { return option.noteSet; } } - console.log(' - Final result:', Nil); - return Nil; + console.log(' - Final result:', null); + return null; } } class TrackCall { @@ -2116,8 +2052,8 @@ class GlobalScope extends Scope { } init() { // set some default values - this.vars.set('time-signature', [4, 4]); - this.vars.set('tempo', 120); + this.vars.set('time-signature', new PlaybackTimeSignatureValue([4, 4])); + this.vars.set('tempo', new PlaybackNumberValue(120)); this.tracks = new Map(); this.metaStatements = []; // @TODO: stop circular dependencies? cache them and mark one as mom @@ -2167,7 +2103,7 @@ class GlobalScope extends Scope { let trackNoteMap = new Map(); for (let [, track] of this.tracks) { let trackNotes = track.execute(songIterator); - if (trackNotes !== Nil) + if (trackNotes) trackNoteMap.set(track.instrument, trackNotes); } return trackNoteMap; @@ -2181,11 +2117,6 @@ class GlobalScope extends Scope { } } -class AnchorArgument { - constructor(anchor) { - this.anchor = anchor; - } -} class BooleanOperator { constructor(...args) { this.args = args; @@ -2220,7 +2151,7 @@ class BooleanNot extends BooleanOperator { } execute(songIterator) { let args = this.resolve_args(songIterator); - return !cast_bool(args[0]); + return new PlaybackBooleanValue(!args[0].toBoolean()); } } class BooleanAnd extends BooleanOperator { @@ -2231,7 +2162,7 @@ class BooleanAnd extends BooleanOperator { // sorry no short-circuiting because this code is prettier // @TODO: add short-circuiting if this actually makes it too slow let args = this.resolve_args(songIterator); - return cast_bool(args[0]) && cast_bool(args[1]); + return new PlaybackBooleanValue(args[0].toBoolean() && args[1].toBoolean()); } } class BooleanOr extends BooleanOperator { @@ -2240,7 +2171,150 @@ class BooleanOr extends BooleanOperator { } execute(songIterator) { let args = this.resolve_args(songIterator); - return cast_bool(args[0]) || cast_bool(args[1]); + return new PlaybackBooleanValue(args[0].toBoolean() || args[1].toBoolean()); + } +} + +class MelodicBeatLiteral { + constructor(opts) { + this.value = new PlaybackMelodicBeatValue(opts.time, opts.pitch, opts.octave); + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + if (this.value.time.time === 'auto') { + return this.indexInMeasure + 1; + } + else { + return this.value.time.time; + } + } + handleInversion(songIterator, pitches) { + let tonicPC = songIterator.song.getTransposedKey(); + let tonicNote = tonal$1.Note.from({ oct: this.getOctave() }, tonicPC); + let tonic = tonal$1.Note.midi(tonicNote); + let outPitches = []; + for (let pitchNote of pitches) { + let pitch = tonal$1.Note.midi(pitchNote); + if (pitch - tonic >= 6) + pitch -= 12; + outPitches.push(tonal$1.Note.fromMidi(pitch)); + } + return outPitches; + } + getAnchorData(songIterator) { + let anchorChord = getAnchorChord(this.value.pitch.anchor, songIterator, this.getTime()); + let root = anchorChordToRoot(anchorChord, this.value.pitch.degree, this.getOctave()); + return [anchorChord, root]; + } + getPitches(songIterator) { + let [anchorChord, root] = this.getAnchorData(songIterator); + let pitches; + if (this.value.pitch.chord) { + // this feels extremely incorrect + // why would anyone need it to work this way + let anchorChordType = tonal$1.Chord.tokenize(anchorChord)[1]; + pitches = tonal$1.Chord.notes(root, anchorChordType); + } + else { + pitches = [root]; + } + if (this.scope.vars.get('invertible')) { + pitches = this.handleInversion(songIterator, pitches); + } + return pitches; + } + /** + * Returns true if the beat is anchored via STEP or ARPEGGIATE + * @returns {boolean} + */ + isDynamic() { + return ['STEP', 'ARPEGGIATE'].includes(this.value.pitch.anchor); + } + getOctave() { + if (this.value.octave === 'inherit') { + return this.scope.vars.get('octave').value; + } + else { + return this.value.octave; + } + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + if (this.value.time.flag === 'STACCATO') { + return Math.min(0.25, duration); + } + else { + return duration; + } + } + getVolume() { + let volume = this.scope.vars.get('volume').value; + if (this.value.time.flag === 'ACCENTED') + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let notes = new NoteSet(); + let time = this.getTime(); // @TODO: this varies with rolling + let pitches = this.getPitches(songIterator); + let duration = this.getDuration(); // @TODO: this varies with rolling + let volume = this.getVolume(); + for (let pitch of pitches) { + notes.push(new Note({ + time: time, + pitch: pitch, + duration: duration, + volume: volume + })); + } + return notes; + } +} +class DrumBeatLiteral { + constructor(opts) { + this.value = new PlaybackDrumBeatValue(opts.time, opts.accented); + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + return this.value.time; + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + return duration; + } + getVolume() { + let volume = this.scope.vars.get('volume').value; + if (this.value.accented) + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let time = this.getTime(); + let duration = this.getDuration(); + let volume = this.getVolume(); + return new NoteSet(new Note({ + time: time, + pitch: AwaitingDrum, + duration: duration, + volume: volume + })); } } @@ -2259,8 +2333,8 @@ class BeatGroupLiteral { for (let i = 0; i < this.measures.length; i++) { let offset = i * 4; // @TODO: pull in actual meter somehow let measureNotes = this.measures[i].execute(songIterator); - if (measureNotes === Nil) - return Nil; // lets a/s abort the beatgroup + if (measureNotes === null) + return null; // lets a/s abort the beatgroup for (let measureNote of measureNotes) { measureNote.time += offset; joinedMeasures.push(measureNote); @@ -2285,7 +2359,7 @@ class BeatGroupLiteral { // later if it's a multi-measure beatgroup) // @TODO: wtf? const nextMeasure = songIterator.getRelative(1); - return MelodicBeatLiteral.normalizeChord(nextMeasure && nextMeasure.beats[0].chord); + return normalizeChordForTonal(nextMeasure && nextMeasure.beats[0].chord); } } class Measure { @@ -2330,8 +2404,8 @@ class Measure { let joined = new NoteSet(); for (let beat of this.beats) { let notes = beat.execute(songIterator); - if (notes === Nil) - return Nil; // lets a and s abort the beatgroup. + if (!notes) + return null; // lets a and s abort the beatgroup. joined.push(...notes); } return joined; @@ -2431,11 +2505,11 @@ let ParserRules = [ {"name": "FunctionCallExpression$macrocall$1", "symbols": ["FunctionCallExpression$macrocall$2", "FunctionCallExpression$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, "_?", "FunctionCallExpression$macrocall$1", "_?", {"literal":")"}], "postprocess": d => new FunctionCall(d[0], d[4])}, {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, {"literal":")"}], "postprocess": d => new FunctionCall(d[0], [])}, - {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": d => new PlaybackNumberValue(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": d => new PlaybackStringValue(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": d => new PlaybackBooleanValue(d[0])}, {"name": "FunctionCallArgument", "symbols": ["PatternExpression"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new AnchorArgument(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new PlaybackAnchorValue(d[0])}, {"name": "FunctionCallArgument", "symbols": [{"literal":"not"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanNot(d[2])}, {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"and"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanAnd(d[0], d[4])}, {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"or"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanOr(d[0], d[4])}, diff --git a/dist/playback.web.mjs b/dist/playback.web.mjs index f0b3336..909abcf 100644 --- a/dist/playback.web.mjs +++ b/dist/playback.web.mjs @@ -970,16 +970,6 @@ var lexer = moo.states({ } }); -let Nil = Symbol('Nil'); -let cast_bool = function (arg) { - if (arg === Nil || arg === false) { - return false; - } - else { - return true; - } -}; - // does this have to be an Error? idc class PlaybackError extends Error { constructor(message, scope) { @@ -1019,8 +1009,8 @@ class FunctionScopeError extends PlaybackError { } } class FunctionArgumentsError extends PlaybackError { - constructor(message, scope) { - super(message, scope); + constructor(message, args, scope) { + super(`${message} (got ${args.map(a => a.toOutputString()).join(', ')})`, scope); } } /* Pattern-related errors */ @@ -1242,230 +1232,184 @@ class NoteSet extends Array { let tonal$1 = {}; (function(n){function t(n){"string"!=typeof n&&(n="");var t=T.exec(n);return t?[t[1].toUpperCase(),t[2].replace(/x/g,"##"),t[3],t[4]]:null}function r(n,t){return n=Math.round(n),(!0===t?G:I)[n%12]+(Math.floor(n/12)-1)}function e(n,t){for(var r=[];t--;r[t]=t+n);return r}function m(n,t){for(var r=[];t--;r[t]=n-t);return r}function i(n,t){return null===n||null===t?[]:nan(t)})}function P(n){return o(n).filter(function(n,t,r){return 0===t||n!==r[t-1]})}function M(n){return "string"!=typeof n?An:_n[n]||(_n[n]=xn(n))}function a(n){var t=(n+1)%7;return t<0?7+t:t}function l(n,t){if(1===arguments.length)return function(t){return l(n,t)};var r=Kn(n),e=Qn(t);if(null===r||null===e)return null;var m=1===r.length?[r[0]+e[0]]:[r[0]+e[0],r[1]+e[1]];return mn(Un(m[0],m[1]))}function c(n,t){if(1===arguments.length)return function(t){return c(n,t)};var r=Kn(n);return null===r?null:mn(Un(r[0]+t))}function s(n,t){if(1===arguments.length)return function(t){return s(n,t)};var r=Kn(n),e=Kn(t);return null===e||null===r?null:e[0]-r[0]}function f(n,t){return 1===arguments.length?function(t){return l(t,n)}:l(t,n)}function d(n,t,r){var e=Qn(n),m=Qn(t);if(null===e||null===m)return null;var i=[e[0]+r*m[0],e[1]+r*m[1]];return Dn(Wn(i))}function p(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,1)}function b(n,t){return 1===arguments.length?function(t){return p(n,t)}:d(n,t,-1)}function h(n,t){if(1===arguments.length)return function(t){return h(n,t)};var r=Kn(n),e=Kn(t);if(null===r||null===e||r.length!==e.length)return null;var m=1===r.length?[e[0]-r[0],-Math.floor(7*(e[0]-r[0])/12)]:[e[0]-r[0],e[1]-r[1]];return Dn(Wn(m))}function v(n,t){if(1===arguments.length)return function(t){return v(n,t)};var r=L(n),e=L(t);return null!==r.midi&&null!==e.midi?e.midi-r.midi:null!==r.chroma&&null!==e.chroma?(e.chroma-r.chroma+12)%12:null}function A(n){if(y(n))return n;if(!Array.isArray(n))return "";var t=[0,0,0,0,0,0,0,0,0,0,0,0];return n.map(nt).forEach(function(n){t[n]=1;}),t.join("")}function g(n){return et=et||i(2048,4095).map(function(n){return n.toString(2)}),"number"==typeof n?et.filter(function(t){return rt(t)===n}):et.slice()}function j(n,t){t=!1!==t;var r=A(n).split("");return Mn(r.map(function(n,e){var m=u(e,r);return t&&"0"===m[0]?null:m.join("")}))}function y(n){return mt.test(n)}function O(n){return y(n)?Mn(n.split("").map(function(n,t){return "1"===n?it[t]:null})):[]}function x(n,t){return 1===arguments.length?function(t){return x(n,t)}:A(n)===A(t)}function _(n,t){return arguments.length>1?_(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t&n)===t})}function z(n,t){return arguments.length>1?z(n)(t):(n=tt(n),function(t){return (t=tt(t))!==n&&(t|n)===t})}function q(n,t){return arguments.length>1?q(n)(t):(n=A(n),function(t){return "1"===n[nt(t)]})}function k(n,t){return 1===arguments.length?function(t){return k(n,t)}:t.filter(q(n))}function S(n,t){var r=D(n);return t=t||r[1],pt(t).map(l(r[0]))}function w(n){var t=D(n);return void 0!==Mt(t[1])}function D(n){if("string"!=typeof n)return ["",""];var t=n.indexOf(" "),r=R(n.substring(0,t))||R(n)||"",e=""!==r?n.substring(r.length+1):n;return [r,e.length?e:""]}function E(n,t){var r=C(n);return t=t||r[1],xt(t).intervals.map(l(r[0]))}function C(n){var r=t(n);return ""===r[0]?["",n]:"A"===r[0]&&"ug"===r[3]?["","aug"]:St.test(r[2])?[r[0]+r[1],r[2]+r[3]]:[r[0]+r[1]+r[2],r[3]]}var $="C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B".split(" "),F=function(n){return "string"!=typeof n?$.slice():$.filter(function(t){var r=t[1]||" ";return -1!==n.indexOf(r)})},G=F(" #"),I=F(" b"),T=/^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)$/,B=Object.freeze({pc:null,name:null,step:null,alt:null,oct:null,octStr:null,chroma:null,midi:null,freq:null}),N=[0,2,4,5,7,9,11],L=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var r=t(n);if(""===r[0]||""!==r[3])return B;var e=r[0],m=r[1],i=r[2],u={letter:e,acc:m,octStr:i};return u.pc=u.letter+u.acc,u.name=u.pc+i,u.step=(u.letter.charCodeAt(0)+3)%7,u.alt="b"===u.acc[0]?-u.acc.length:u.acc.length,u.oct=i.length?+i:null,u.chroma=(N[u.step]+u.alt+120)%12,u.midi=null!==u.oct?N[u.step]+u.alt+12*(u.oct+1):null,u.freq=J(u.midi),Object.freeze(u)}),R=function(n){return L(n).name},U=function(n){return L(n).pc},H=function(n){return L(n).midi||+n||null},J=function(n,t){return void 0===t&&(t=440),"number"==typeof n?Math.pow(2,(n-69)/12)*t:null},K=function(n){return L(n).freq||J(n)},Q=Math.log(2),V=Math.log(440),W=function(n){var t=12*(Math.log(n)-V)/Q+69;return Math.round(100*t)/100},X=function(n){return L(n).chroma},Y=function(n){return L(n).oct},Z=function(n){return "CDEFGAB"[n]},nn=function(n,t){return Array(t+1).join(n)},tn=function(n,t){return "number"!=typeof n?"":t(n)},rn=function(n){return tn(n,function(n){return n<0?nn("b",-n):nn("#",n)})},en=function(n,t){void 0===n&&(n={}),void 0===t&&(t=null);var r=t?Object.assign({},L(t),n):n,e=r.step,m=r.alt,i=r.oct,u=Z(e);if(!u)return null;var o=u+rn(m);return i||0===i?o+i:o},mn=en,un=function(n,t){var e=L(n),m=e.alt,i=e.chroma,u=e.midi;if(null===i)return null;var o=!1===t?m<0:m>0;return null===u?U(r(i,o)):r(u,o)},on=function(n){return un(n,!1)},Pn=Object.freeze({names:F,tokenize:t,props:L,name:R,pc:U,midi:H,midiToFreq:J,freq:K,freqToMidi:W,chroma:X,oct:Y,stepToLetter:Z,altToAcc:rn,from:en,build:mn,fromMidi:r,simplify:un,enharmonic:on}),Mn=function(n){return n.filter(function(n){return 0===n||n})},an=function(n){var t=H(n);return null!==t?t:H(n+"-100")},ln=function(n,t){void 0===t&&(t=Math.random);for(var r,e,m=n.length;m;)r=t()*m--|0,e=n[m],n[m]=n[r],n[r]=e;return n},cn=function(n){return 0===n.length?[[]]:cn(n.slice(1)).reduce(function(t,r){return t.concat(n.map(function(t,e){var m=r.slice();return m.splice(e,0,n[0]),m}))},[])},sn=Object.freeze({range:i,rotate:u,compact:Mn,sort:o,unique:P,shuffle:ln,permutations:cn}),fn=new RegExp("^([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})|(AA|A|P|M|m|d|dd)([-+]?\\d+)$"),dn=[0,2,4,5,7,9,11],pn=[0,1,2,3,4,5,6,5,4,3,2,1],bn="1P 2m 2M 3m 3M 4P 5P 6m 6M 7m 7M 8P".split(" "),hn=function(n){return "string"!=typeof n?bn.slice():bn.filter(function(t){return -1!==n.indexOf(t[1])})},vn=function(n){var t=fn.exec(n);return null===t?null:t[1]?[t[1],t[2]]:[t[4],t[3]]},An=Object.freeze({name:null,num:null,q:null,step:null,alt:null,dir:null,type:null,simple:null,semitones:null,chroma:null}),gn=function(n,t){return Array(Math.abs(t)+1).join(n)},jn=function(n,t){return "M"===t&&"M"===n?0:"P"===t&&"P"===n?0:"m"===t&&"M"===n?-1:/^A+$/.test(t)?t.length:/^d+$/.test(t)?"P"===n?-t.length:-t.length-1:null},yn=function(n,t){return 0===t?"M"===n?"M":"P":-1===t&&"M"===n?"m":t>0?gn("A",t):t<0?gn("d","P"===n?t:t+1):null},On=function(n){return (Math.abs(n)-1)%7},xn=function(n){var t=vn(n);if(null===t)return An;var r={num:+t[0],q:t[1]};return r.step=On(r.num),r.type="PMMPPMM"[r.step],"M"===r.type&&"P"===r.q?An:(r.name=""+r.num+r.q,r.dir=r.num<0?-1:1,r.simple=8===r.num||-8===r.num?r.num:r.dir*(r.step+1),r.alt=jn(r.type,r.q),r.oct=Math.floor((Math.abs(r.num)-1)/7),r.semitones=r.dir*(dn[r.step]+r.alt+12*r.oct),r.chroma=(r.dir*(dn[r.step]+r.alt)%12+12)%12,Object.freeze(r))},_n={},zn=function(n){return M(n).num},qn=function(n){return M(n).name},kn=function(n){return M(n).semitones},Sn=function(n){return M(n).chroma},wn=function(n){return "string"==typeof n&&(n=M(n).chroma),"number"==typeof n?pn[n%12]:null},Dn=function(n){void 0===n&&(n={});var t=n.num,r=n.step,e=n.alt,m=n.oct;void 0===m&&(m=1);var i=n.dir;if(void 0!==r&&(t=r+1+7*m),void 0===t)return null;var u=i<0?"-":"",o="PMMPPMM"[On(t)];return u+t+yn(o,e)},En=function(n){var t=M(n);return t===An?null:t.simple+t.q},Cn=function(n){var t=M(n);if(t===An)return null;var r=(7-t.step)%7,e="P"===t.type?-t.alt:-(t.alt+1);return Dn({step:r,alt:e,oct:t.oct,dir:t.dir})},$n=[1,2,2,3,3,4,5,5,6,6,7,7],Fn="P m M m M P d P m M m M".split(" "),Gn=function(n){var t=n<0?-1:1,r=Math.abs(n),e=r%12,m=Math.floor(r/12);return t*($n[e]+7*m)+Fn[e]},In=Object.freeze({names:hn,tokenize:vn,props:M,num:zn,name:qn,semitones:kn,chroma:Sn,ic:wn,build:Dn,simplify:En,invert:Cn,fromSemitones:Gn}),Tn=[0,2,4,-1,1,3,5],Bn=function(n){return Math.floor(7*n/12)},Nn=Tn.map(Bn),Ln=function(n){var t=n.step,r=n.alt,e=n.oct,m=n.dir;void 0===m&&(m=1);var i=Tn[t]+7*r;return null===e?[m*i]:[m*i,m*(e-Nn[t]-4*r)]},Rn=[3,0,4,1,5,2,6],Un=function(n,t,r){var e=Rn[a(n)],m=Math.floor((n+1)/7);return void 0===t?{step:e,alt:m,dir:r}:{step:e,alt:m,oct:t+4*m+Nn[e],dir:r}},Hn=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}},Jn=function(n){return Hn(function(t){var r=n(t);return null===r.name?null:Ln(r)})},Kn=Jn(L),Qn=Jn(M),Vn=function(n){return 7*n[0]+12*n[1]<0},Wn=function(n){return Vn(n)?Un(-n[0],-n[1],-1):Un(n[0],n[1],1)},Xn=Object.freeze({transpose:l,trFifths:c,fifths:s,transposeBy:f,addIntervals:d,add:p,subtract:b,interval:h,semitones:v}),Yn={chromatic:["1P 2m 2M 3m 3M 4P 4A 5P 6m 6M 7m 7M"],lydian:["1P 2M 3M 4A 5P 6M 7M"],major:["1P 2M 3M 4P 5P 6M 7M",["ionian"]],mixolydian:["1P 2M 3M 4P 5P 6M 7m",["dominant"]],dorian:["1P 2M 3m 4P 5P 6M 7m"],aeolian:["1P 2M 3m 4P 5P 6m 7m",["minor"]],phrygian:["1P 2m 3m 4P 5P 6m 7m"],locrian:["1P 2m 3m 4P 5d 6m 7m"],altered:["1P 2m 3m 3M 5d 6m 7m",["super locrian","diminished whole tone","pomeroy"]],iwato:["1P 2m 4P 5d 7m"],hirajoshi:["1P 2M 3m 5P 6m"],kumoijoshi:["1P 2m 4P 5P 6m"],pelog:["1P 2m 3m 5P 6m"],prometheus:["1P 2M 3M 4A 6M 7m"],ritusen:["1P 2M 4P 5P 6M"],scriabin:["1P 2m 3M 5P 6M"],piongio:["1P 2M 4P 5P 6M 7m"],augmented:["1P 2A 3M 5P 5A 7M"],neopolitan:["1P 2m 3m 4P 5P 6m 7M"],diminished:["1P 2M 3m 4P 5d 6m 6M 7M"],egyptian:["1P 2M 4P 5P 7m"],oriental:["1P 2m 3M 4P 5d 6M 7m"],spanish:["1P 2m 3M 4P 5P 6m 7m",["phrygian major"]],flamenco:["1P 2m 3m 3M 4A 5P 7m"],balinese:["1P 2m 3m 4P 5P 6m 7M"],persian:["1P 2m 3M 4P 5d 6m 7M"],bebop:["1P 2M 3M 4P 5P 6M 7m 7M"],enigmatic:["1P 2m 3M 5d 6m 7m 7M"],ichikosucho:["1P 2M 3M 4P 5d 5P 6M 7M"],"melodic minor":["1P 2M 3m 4P 5P 6M 7M"],"melodic minor second mode":["1P 2m 3m 4P 5P 6M 7m"],"lydian augmented":["1P 2M 3M 4A 5A 6M 7M"],"lydian dominant":["1P 2M 3M 4A 5P 6M 7m",["lydian b7"]],"melodic minor fifth mode":["1P 2M 3M 4P 5P 6m 7m",["hindu","mixolydian b6M"]],"locrian #2":["1P 2M 3m 4P 5d 6m 7m"],"locrian major":["1P 2M 3M 4P 5d 6m 7m",["arabian"]],"major pentatonic":["1P 2M 3M 5P 6M",["pentatonic"]],"lydian pentatonic":["1P 3M 4A 5P 7M",["chinese"]],"mixolydian pentatonic":["1P 3M 4P 5P 7m",["indian"]],"locrian pentatonic":["1P 3m 4P 5d 7m",["minor seven flat five pentatonic"]],"minor pentatonic":["1P 3m 4P 5P 7m"],"minor six pentatonic":["1P 3m 4P 5P 6M"],"minor hexatonic":["1P 2M 3m 4P 5P 7M"],"flat three pentatonic":["1P 2M 3m 5P 6M",["kumoi"]],"flat six pentatonic":["1P 2M 3M 5P 6m"],"major flat two pentatonic":["1P 2m 3M 5P 6M"],"whole tone pentatonic":["1P 3M 5d 6m 7m"],"ionian pentatonic":["1P 3M 4P 5P 7M"],"lydian #5P pentatonic":["1P 3M 4A 5A 7M"],"lydian dominant pentatonic":["1P 3M 4A 5P 7m"],"minor #7M pentatonic":["1P 3m 4P 5P 7M"],"super locrian pentatonic":["1P 3m 4d 5d 7m"],"in-sen":["1P 2m 4P 5P 7m"],"vietnamese 1":["1P 3m 4P 5P 6m"],"vietnamese 2":["1P 3m 4P 5P 7m"],"prometheus neopolitan":["1P 2m 3M 4A 6M 7m"],"major blues":["1P 2M 3m 3M 5P 6M"],"minor blues":["1P 3m 4P 5d 5P 7m",["blues"]],"composite blues":["1P 2M 3m 3M 4P 5d 5P 6M 7m"],"augmented heptatonic":["1P 2A 3M 4P 5P 5A 7M"],"dorian #4":["1P 2M 3m 4A 5P 6M 7m"],"lydian diminished":["1P 2M 3m 4A 5P 6M 7M"],"whole tone":["1P 2M 3M 4A 5A 7m"],"leading whole tone":["1P 2M 3M 4A 5A 7m 7M"],"harmonic minor":["1P 2M 3m 4P 5P 6m 7M"],"lydian minor":["1P 2M 3M 4A 5P 6m 7m"],"neopolitan minor":["1P 2m 3m 4P 5P 6m 7M"],"neopolitan major":["1P 2m 3m 4P 5P 6M 7M",["dorian b2"]],"neopolitan major pentatonic":["1P 3M 4P 5d 7m"],"romanian minor":["1P 2M 3m 5d 5P 6M 7m"],"double harmonic lydian":["1P 2m 3M 4A 5P 6m 7M"],"harmonic major":["1P 2M 3M 4P 5P 6m 7M"],"double harmonic major":["1P 2m 3M 4P 5P 6m 7M",["gypsy"]],"hungarian minor":["1P 2M 3m 4A 5P 6m 7M"],"hungarian major":["1P 2A 3M 4A 5P 6M 7m"],"spanish heptatonic":["1P 2m 3m 3M 4P 5P 6m 7m"],"todi raga":["1P 2m 3m 4A 5P 6m 7M"],"malkos raga":["1P 3m 4P 6m 7m"],"kafi raga":["1P 3m 3M 4P 5P 6M 7m 7M"],"purvi raga":["1P 2m 3M 4P 4A 5P 6m 7M"],"bebop dominant":["1P 2M 3M 4P 5P 6M 7m 7M"],"bebop minor":["1P 2M 3m 3M 4P 5P 6M 7m"],"bebop major":["1P 2M 3M 4P 5P 5A 6M 7M"],"bebop locrian":["1P 2m 3m 4P 5d 5P 6m 7m"],"minor bebop":["1P 2M 3m 4P 5P 6m 7m 7M"],"mystery #1":["1P 2m 3M 5d 6m 7m"],"minor six diminished":["1P 2M 3m 4P 5P 6m 6M 7M"],"ionian augmented":["1P 2M 3M 4P 5A 6M 7M"],"lydian #9":["1P 2m 3M 4A 5P 6M 7M"],"six tone symmetric":["1P 2m 3M 4P 5A 6M"]},Zn={M:["1P 3M 5P",["Major",""]],M13:["1P 3M 5P 7M 9M 13M",["maj13","Maj13"]],M6:["1P 3M 5P 13M",["6"]],M69:["1P 3M 5P 6M 9M",["69"]],M7add13:["1P 3M 5P 6M 7M 9M"],M7b5:["1P 3M 5d 7M"],M7b6:["1P 3M 6m 7M"],M7b9:["1P 3M 5P 7M 9m"],M7sus4:["1P 4P 5P 7M"],M9:["1P 3M 5P 7M 9M",["maj9","Maj9"]],M9b5:["1P 3M 5d 7M 9M"],M9sus4:["1P 4P 5P 7M 9M"],Madd9:["1P 3M 5P 9M",["2","add9","add2"]],Maj7:["1P 3M 5P 7M",["maj7","M7"]],Mb5:["1P 3M 5d"],Mb6:["1P 3M 13m"],Msus2:["1P 2M 5P",["add9no3","sus2"]],Msus4:["1P 4P 5P",["sus","sus4"]],Maddb9:["1P 3M 5P 9m"],m:["1P 3m 5P"],m11:["1P 3m 5P 7m 9M 11P",["_11"]],m11b5:["1P 3m 7m 12d 2M 4P",["h11","_11b5"]],m13:["1P 3m 5P 7m 9M 11P 13M",["_13"]],m6:["1P 3m 4P 5P 13M",["_6"]],m69:["1P 3m 5P 6M 9M",["_69"]],m7:["1P 3m 5P 7m",["minor7","_","_7"]],m7add11:["1P 3m 5P 7m 11P",["m7add4"]],m7b5:["1P 3m 5d 7m",["half-diminished","h7","_7b5"]],m9:["1P 3m 5P 7m 9M",["_9"]],m9b5:["1P 3m 7m 12d 2M",["h9","-9b5"]],mMaj7:["1P 3m 5P 7M",["mM7","_M7"]],mMaj7b6:["1P 3m 5P 6m 7M",["mM7b6"]],mM9:["1P 3m 5P 7M 9M",["mMaj9","-M9"]],mM9b6:["1P 3m 5P 6m 7M 9M",["mMaj9b6"]],mb6M7:["1P 3m 6m 7M"],mb6b9:["1P 3m 6m 9m"],o:["1P 3m 5d",["mb5","dim"]],o7:["1P 3m 5d 13M",["diminished","m6b5","dim7"]],o7M7:["1P 3m 5d 6M 7M"],oM7:["1P 3m 5d 7M"],sus24:["1P 2M 4P 5P",["sus4add9"]],madd4:["1P 3m 4P 5P"],madd9:["1P 3m 5P 9M"],4:["1P 4P 7m 10m",["quartal"]],5:["1P 5P"],7:["1P 3M 5P 7m",["Dominant","Dom"]],9:["1P 3M 5P 7m 9M",["79"]],11:["1P 5P 7m 9M 11P"],13:["1P 3M 5P 7m 9M 13M",["13_"]],64:["5P 8P 10M"],"M#5":["1P 3M 5A",["augmented","maj#5","Maj#5","+","aug"]],"M#5add9":["1P 3M 5A 9M",["+add9"]],"M13#11":["1P 3M 5P 7M 9M 11A 13M",["maj13#11","Maj13#11","M13+4","M13#4"]],"M6#11":["1P 3M 5P 6M 11A",["M6b5","6#11","6b5"]],"M69#11":["1P 3M 5P 6M 9M 11A"],"M7#11":["1P 3M 5P 7M 11A",["maj7#11","Maj7#11","M7+4","M7#4"]],"M7#5":["1P 3M 5A 7M",["maj7#5","Maj7#5","maj9#5","M7+"]],"M7#5sus4":["1P 4P 5A 7M"],"M7#9#11":["1P 3M 5P 7M 9A 11A"],"M9#11":["1P 3M 5P 7M 9M 11A",["maj9#11","Maj9#11","M9+4","M9#4"]],"M9#5":["1P 3M 5A 7M 9M",["Maj9#5"]],"M9#5sus4":["1P 4P 5A 7M 9M"],"11b9":["1P 5P 7m 9m 11P"],"13#11":["1P 3M 5P 7m 9M 11A 13M",["13+4","13#4"]],"13#9":["1P 3M 5P 7m 9A 13M",["13#9_"]],"13#9#11":["1P 3M 5P 7m 9A 11A 13M"],"13b5":["1P 3M 5d 6M 7m 9M"],"13b9":["1P 3M 5P 7m 9m 13M"],"13b9#11":["1P 3M 5P 7m 9m 11A 13M"],"13no5":["1P 3M 7m 9M 13M"],"13sus4":["1P 4P 5P 7m 9M 13M",["13sus"]],"69#11":["1P 3M 5P 6M 9M 11A"],"7#11":["1P 3M 5P 7m 11A",["7+4","7#4","7#11_","7#4_"]],"7#11b13":["1P 3M 5P 7m 11A 13m",["7b5b13"]],"7#5":["1P 3M 5A 7m",["+7","7aug","aug7"]],"7#5#9":["1P 3M 5A 7m 9A",["7alt","7#5#9_","7#9b13_"]],"7#5b9":["1P 3M 5A 7m 9m"],"7#5b9#11":["1P 3M 5A 7m 9m 11A"],"7#5sus4":["1P 4P 5A 7m"],"7#9":["1P 3M 5P 7m 9A",["7#9_"]],"7#9#11":["1P 3M 5P 7m 9A 11A",["7b5#9"]],"7#9#11b13":["1P 3M 5P 7m 9A 11A 13m"],"7#9b13":["1P 3M 5P 7m 9A 13m"],"7add6":["1P 3M 5P 7m 13M",["67","7add13"]],"7b13":["1P 3M 7m 13m"],"7b5":["1P 3M 5d 7m"],"7b6":["1P 3M 5P 6m 7m"],"7b9":["1P 3M 5P 7m 9m"],"7b9#11":["1P 3M 5P 7m 9m 11A",["7b5b9"]],"7b9#9":["1P 3M 5P 7m 9m 9A"],"7b9b13":["1P 3M 5P 7m 9m 13m"],"7b9b13#11":["1P 3M 5P 7m 9m 11A 13m",["7b9#11b13","7b5b9b13"]],"7no5":["1P 3M 7m"],"7sus4":["1P 4P 5P 7m",["7sus"]],"7sus4b9":["1P 4P 5P 7m 9m",["susb9","7susb9","7b9sus","7b9sus4","phryg"]],"7sus4b9b13":["1P 4P 5P 7m 9m 13m",["7b9b13sus4"]],"9#11":["1P 3M 5P 7m 9M 11A",["9+4","9#4","9#11_","9#4_"]],"9#11b13":["1P 3M 5P 7m 9M 11A 13m",["9b5b13"]],"9#5":["1P 3M 5A 7m 9M",["9+"]],"9#5#11":["1P 3M 5A 7m 9M 11A"],"9b13":["1P 3M 7m 9M 13m"],"9b5":["1P 3M 5d 7m 9M"],"9no5":["1P 3M 7m 9M"],"9sus4":["1P 4P 5P 7m 9M",["9sus"]],"m#5":["1P 3m 5A",["m+","mb6"]],"m11A 5":["1P 3m 6m 7m 9M 11P"],"m7#5":["1P 3m 6m 7m"],"m9#5":["1P 3m 6m 7m 9M"],"+add#9":["1P 3M 5A 9A"]},nt=function(n){return X(n)||Sn(n)||0},tt=function(n){return parseInt(A(n),2)},rt=function(n){return n.replace(/0/g,"").length},et=null,mt=/^[01]{12}$/,it="1P 2m 2M 3m 3M 4P 5d 5P 6m 6M 7m 7M".split(" "),ut=Object.freeze({chroma:A,chromas:g,modes:j,isChroma:y,intervals:O,isEqual:x,isSubsetOf:_,isSupersetOf:z,includes:q,filter:k}),ot=function(n){var t=Object.keys(n).sort(),r=[],e=[],m=function(n,t,m){r[n]=t,e[m]=e[m]||[],e[m].push(n);};t.forEach(function(t){var r=n[t][0].split(" "),e=n[t][1],i=A(r);m(t,r,i),e&&e.forEach(function(n){return m(n,r,i)});});var i=Object.keys(r).sort(),u=function(n){return r[n]};return u.names=function(n){return "string"==typeof n?(e[n]||[]).slice():(!0===n?i:t).slice()},u},Pt=function(n,t){var r=function(r){return n(r)||t(r)};return r.names=function(r){return n.names(r).concat(t.names(r))},r},Mt=ot(Yn),at=ot(Zn),lt=Pt(Mt,at),ct=Object.freeze({dictionary:ot,combine:Pt,scale:Mt,chord:at,pcset:lt}),st=Object.freeze({name:null,intervals:[],names:[],chroma:null,setnum:null}),ft=function(n,t){return function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=Mt(n);if(!t)return st;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=Mt.names(r.chroma),Object.freeze(r)},{}),dt=Mt.names,pt=function(n){var t=D(n);return ft(t[1]).intervals},bt=function(n){var t=pt(n),r=S(n);return j(t).map(function(n,e){var m=Mt.names(n)[0];if(m)return [r[e]||t[e],m]}).filter(function(n){return n})},ht=function(n){var t=_(pt(n));return at.names().filter(function(n){return t(at(n))})},vt=function(n){var t=Mn(n.map(U));if(!t.length)return t;var r=t[0],e=P(t);return u(e.indexOf(r),e)},At=function(n){if(!pt(n).length)return [];var t=z(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},gt=function(n){var t=_(pt(n));return Mt.names().filter(function(n){return t(Mt(n))})},jt=Object.freeze({props:ft,names:dt,intervals:pt,notes:S,exists:w,tokenize:D,modeNames:bt,chords:ht,toScale:vt,supersets:At,subsets:gt}),yt=at.names,Ot=Object.freeze({name:null,names:[],intervals:[],chroma:null,setnum:null}),xt=function(n,t){return void 0===t&&(t={}),function(r){return t[r]||(t[r]=n(r))}}(function(n){var t=at(n);if(!t)return Ot;var r={intervals:t,name:n};return r.chroma=A(t),r.setnum=parseInt(r.chroma,2),r.names=at.names(r.chroma),r}),_t=function(n){return xt(C(n)[1]).intervals},zt=function(n){return void 0!==at(C(n)[1])},qt=function(n){if(!_t(n).length)return [];var t=z(_t(n));return at.names().filter(function(n){return t(at(n))})},kt=function(n){var t=_(_t(n));return at.names().filter(function(n){return t(at(n))})},St=/^(6|64|7|9|11|13)$/,wt=Object.freeze({names:yt,props:xt,intervals:_t,notes:E,exists:zt,supersets:qt,subsets:kt,tokenize:C}),Dt=l,Et=h,Ct=L,$t=H,Ft=K,Gt=at,It=Mt;n.Array=sn,n.Note=Pn,n.Interval=In,n.Distance=Xn,n.Scale=jt,n.Chord=wt,n.PcSet=ut,n.Dictionary=ct,n.transpose=Dt,n.interval=Et,n.note=Ct,n.midi=$t,n.freq=Ft,n.chord=Gt,n.scale=It,Object.defineProperty(n,"__esModule",{value:!0});})(tonal$1); -//import {Nil} from './type_utils.js'; -class MelodicBeatLiteral { - constructor(opts) { - this.time = opts.time || { time: 'auto' }; - this.pitch = opts.pitch; - this.octave = opts.octave || 'inherit'; - this.scope = null; - this.parentMeasure = null; - this.indexInMeasure = null; - this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation - } - init(scope, parentMeasure, indexInMeasure) { - this.scope = scope; - this.parentMeasure = parentMeasure; - this.indexInMeasure = indexInMeasure; - } - getTime() { - if (this.time.time === 'auto') { - return this.indexInMeasure + 1; - } - else { - return this.time.time; - } - } - /** - * Normalize a chord into a form tonal can handle - * @param {string} [chord=''] - * @return {string} - */ - static normalizeChord(chord = '') { - return chord - .replace(/-/g, '_') // tonal uses _ over - for minor7 - .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? - } - static chordToScaleName(chord) { - let chordType = tonal$1.Chord.tokenize(chord)[1]; - // @TODO: make this more robust - let names = tonal$1.Chord.props(chordType).names; - if (names.includes('dim')) - return 'diminished'; - if (names.includes('aug')) - return 'augmented'; - if (names.includes('Major')) - return 'major'; - if (names.includes('minor')) - return 'minor'; - if (names.includes('minor7')) - return 'dorian'; - if (names.includes('Dominant')) - return 'mixolydian'; - // if none of the above match, do our best to find the closest fit - let closestScale = 'major'; - names.forEach(name => { - if (name.startsWith('dim')) - closestScale = 'diminished'; - if (name.startsWith('aug')) - closestScale = 'augmented'; - if (name.startsWith('M')) - closestScale = 'major'; - if (name.startsWith('m')) - closestScale = 'minor'; - }); - return closestScale; - } - handleInversion(songIterator, pitches) { - let tonicPC = songIterator.song.getTransposedKey(); - let tonicNote = tonal$1.Note.from({ oct: this.getOctave() }, tonicPC); - let tonic = tonal$1.Note.midi(tonicNote); - let outPitches = []; - for (let pitchNote of pitches) { - let pitch = tonal$1.Note.midi(pitchNote); - if (pitch - tonic >= 6) - pitch -= 12; - outPitches.push(tonal$1.Note.fromMidi(pitch)); - } - return outPitches; - } - static getAnchorChord(anchor, songIterator, currentTime) { - let anchorChord; - switch (anchor) { - case 'KEY': { - anchorChord = songIterator.song.getTransposedKey(); - } - case 'NEXT': { - let nextMeasure = songIterator.getRelative(1); - if (nextMeasure) { - anchorChord = nextMeasure.beats[0].chord; - } - else { - anchorChord = songIterator.song.getTransposedKey(); - } +function normalizeChordForTonal(chord = '') { + return chord + .replace(/-/g, '_') // tonal uses _ over - for minor7 + .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? +} +function getAnchorChord(anchor, songIterator, currentTime) { + let anchorChord; + switch (anchor) { + case 'KEY': { + anchorChord = songIterator.song.getTransposedKey(); + } + case 'NEXT': { + let nextMeasure = songIterator.getRelative(1); + if (nextMeasure) { + anchorChord = nextMeasure.beats[0].chord; } - case 'STEP': - case 'ARPEGGIATE': - default: { - // crawl backward through this measure to get the last set beat - let lastSetBeat = Math.floor(currentTime); - let iteratorMeasure = songIterator.getRelative(0); - if (!iteratorMeasure) - break; - do { - const beat = iteratorMeasure.beats[lastSetBeat]; - anchorChord = beat && beat.chord; - lastSetBeat--; - } while (!anchorChord); + else { + anchorChord = songIterator.song.getTransposedKey(); } } - return this.normalizeChord(anchorChord); - } - static anchorChordToRoot(anchorChord, degree, octave) { - let anchorTonic = tonal$1.Chord.tokenize(anchorChord)[0]; - let anchorScaleName = this.chordToScaleName(anchorChord); - let scalePCs = tonal$1.Scale.notes(anchorTonic, anchorScaleName); - let rootPC = scalePCs[degree - 1]; - return tonal$1.Note.from({ oct: octave }, rootPC); - } - getAnchorData(songIterator) { - let anchorChord = MelodicBeatLiteral.getAnchorChord(this.pitch.anchor, songIterator, this.getTime()); - let root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, this.pitch.degree, this.getOctave()); - return [anchorChord, root]; - } - getPitches(songIterator) { - let [anchorChord, root] = this.getAnchorData(songIterator); - let pitches; - if (this.pitch.chord) { - // this feels extremely incorrect - // why would anyone need it to work this way - let anchorChordType = tonal$1.Chord.tokenize(anchorChord)[1]; - pitches = tonal$1.Chord.notes(root, anchorChordType); - } - else { - pitches = [root]; - } - if (this.scope.vars.get('invertible')) { - pitches = this.handleInversion(songIterator, pitches); - } - return pitches; - } - /** - * Returns true if the beat is anchored via STEP or ARPEGGIATE - * @returns {boolean} - */ - isDynamic() { - return ['STEP', 'ARPEGGIATE'].includes(this.pitch.anchor); - } - getOctave() { - if (this.octave === 'inherit') { - return this.scope.vars.get('octave'); - } - else { - return this.octave; - } + case 'STEP': + case 'ARPEGGIATE': + default: { + // crawl backward through this measure to get the last set beat + let lastSetBeat = Math.floor(currentTime); + let iteratorMeasure = songIterator.getRelative(0); + if (!iteratorMeasure) + break; + do { + const beat = iteratorMeasure.beats[lastSetBeat]; + anchorChord = beat && beat.chord; + lastSetBeat--; + } while (!anchorChord); + } + } + return normalizeChordForTonal(anchorChord); +} +function anchorChordToRoot(anchorChord, degree, octave) { + let anchorTonic = tonal$1.Chord.tokenize(anchorChord)[0]; + let anchorScaleName = chordToScaleName(anchorChord); + let scalePCs = tonal$1.Scale.notes(anchorTonic, anchorScaleName); + let rootPC = scalePCs[degree - 1]; + return tonal$1.Note.from({ oct: octave }, rootPC); +} +function chordToScaleName(chord) { + let chordType = tonal$1.Chord.tokenize(chord)[1]; + // @TODO: make this more robust + let names = tonal$1.Chord.props(chordType).names; + if (names.includes('dim')) + return 'diminished'; + if (names.includes('aug')) + return 'augmented'; + if (names.includes('Major')) + return 'major'; + if (names.includes('minor')) + return 'minor'; + if (names.includes('minor7')) + return 'dorian'; + if (names.includes('Dominant')) + return 'mixolydian'; + // if none of the above match, do our best to find the closest fit + let closestScale = 'major'; + names.forEach(name => { + if (name.startsWith('dim')) + closestScale = 'diminished'; + if (name.startsWith('aug')) + closestScale = 'augmented'; + if (name.startsWith('M')) + closestScale = 'major'; + if (name.startsWith('m')) + closestScale = 'minor'; + }); + return closestScale; +} + +const anchorReverseMap = { 'KEY': 'k', 'NEXT': 'n', 'STEP': 's', 'ARPEGGIATE': 'a' }; +class PlaybackAnchorValue { + constructor(value) { + this.type = 'anchor'; + this.value = value; } - getDuration() { - let duration; - duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); - if (this.time.flag === 'STACCATO') { - return Math.min(0.25, duration); - } - else { - return duration; - } + toBoolean() { return true; } + toOutputString() { return anchorReverseMap[this.value]; } +} +class PlaybackBeatValue { + constructor() { + this.type = null; } - getVolume() { - let volume = this.scope.vars.get('volume'); - if (this.time.flag === 'ACCENTED') - volume = Math.min(1, volume += .1); - return volume; + toBoolean() { return true; } +} +class PlaybackMelodicBeatValue extends PlaybackBeatValue { + constructor(time = { time: 'auto' }, pitch, octave = 'inherit') { + super(); + this.type = 'melodic_beat'; + this.value = { + time: null, + pitch: null, + octave: null, + }; + this.value.time = time; + this.value.pitch = pitch; + this.value.octave = octave; + } + toOutputString() { + const timeFlag = this.time.flag ? (this.time.flag === 'ACCENTED' ? 'a' : 's') : ''; + const timePart = `${this.time.time === 'auto' ? '' : this.time.time}${timeFlag}`; + const pitchAnchor = this.pitch.anchor ? anchorReverseMap[this.pitch.anchor] : ''; + const pitchRoll = this.pitch.roll ? (this.pitch.roll === 'ROLL_UP' ? 'r' : 'rd') : ''; + const pitchPart = `:${pitchAnchor}${this.pitch.degree || ''}${this.pitch.chord ? 'c' : ''}${pitchRoll}`; + const octavePart = this.octave === 'inherit' ? '' : `:${this.octave}`; + return `${timePart}${pitchPart}${octavePart}`; + } + get time() { return this.value.time; } + get pitch() { return this.value.pitch; } + get octave() { return this.value.octave; } +} +class PlaybackDrumBeatValue extends PlaybackBeatValue { + constructor(time, accented = false) { + super(); + this.type = 'drum_beat'; + this.value = { + time: null, + accented: null, + }; + this.value.time = time; + this.value.accented = accented; } - execute(songIterator) { - let notes = new NoteSet(); - let time = this.getTime(); // @TODO: this varies with rolling - let pitches = this.getPitches(songIterator); - let duration = this.getDuration(); // @TODO: this varies with rolling - let volume = this.getVolume(); - for (let pitch of pitches) { - notes.push(new Note({ - time: time, - pitch: pitch, - duration: duration, - volume: volume - })); - } - return notes; + toOutputString() { + return `${this.time}${this.accented ? 'a' : ''}`; } + get time() { return this.value.time; } + get accented() { return this.value.accented; } } -class DrumBeatLiteral { - constructor(opts) { - this.time = opts.time; - this.accented = opts.accented || false; - this.scope = null; - this.parentMeasure = null; - this.indexInMeasure = null; - } - init(scope, parentMeasure, indexInMeasure) { - this.scope = scope; - this.parentMeasure = parentMeasure; - this.indexInMeasure = indexInMeasure; + +class PlaybackNilValue { + constructor() { + this.type = 'Nil'; + this.value = null; } - getTime() { - return this.time; + toBoolean() { return false; } + toOutputString() { return 'Nil'; } +} +class PlaybackStringValue { + constructor(value) { + this.type = 'string'; + this.value = value; } - getDuration() { - let duration; - duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); - return duration; + toBoolean() { return this.value !== ''; } + toOutputString() { + // @TODO: store raw value from tokenizer? (which may not always exist for programmatically-generated strings) + // At least this is consistent... + return `"${this.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`; } - getVolume() { - let volume = this.scope.vars.get('volume'); - if (this.accented) - volume = Math.min(1, volume += .1); - return volume; +} +class PlaybackNumberValue { + constructor(value) { + this.type = 'number'; + this.value = value; + } + toInteger() { return Math.floor(this.value); } + toBoolean() { return this.value !== 0; } + toOutputString() { return this.value.toString(); } +} +class PlaybackBooleanValue { + constructor(value) { + this.type = 'boolean'; + this.value = value; } - execute(songIterator) { - let time = this.getTime(); - let duration = this.getDuration(); - let volume = this.getVolume(); - return new NoteSet(new Note({ - time: time, - pitch: AwaitingDrum, - duration: duration, - volume: volume - })); + toBoolean() { return this.value; } + toOutputString() { return this.value ? 'true' : 'false'; } +} +class PlaybackTimeSignatureValue { + constructor(value) { + this.type = 'time_signature'; + this.value = value; } + toBoolean() { return true; } + toOutputString() { return `${this.value[0]} / ${this.value[1]}`; } } let definitions = new Map(); @@ -1481,38 +1425,25 @@ function assertArgTypes(identifier, args, types, scope) { if (types == '*') return; if (args.length != types.length) { - throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, scope); + throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, args, scope); } for (let i in args) { if (types[i] == '*') continue; let arg = args[i]; if (arg instanceof FunctionCall) { - arg = arg.returns; - if (arg == '*') { + if (arg.returns == '*') { continue; // what's the correct functionality here? cry? } - else if (typeof types[i] == 'string') { - if (arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); - } - } else { - if (arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); + if (arg.returns !== types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, args, scope); } } } else { - if (typeof types[i] == 'string') { - if (typeof arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, scope); - } - } - else { - if (!(arg instanceof types[i])) { - throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i].name}.`, scope); - } + if (arg.type !== types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i) + 1} of "${identifier}" must be a ${types[i]}.`, args, scope); } } } @@ -1585,7 +1516,7 @@ let define$1 = function (identifier, opts, func) { scope: opts.scope || 'no-meta', execute: (args, songIterator, scope) => { let argErr = message => { - throw new FunctionArgumentsError(message, scope); + throw new FunctionArgumentsError(message, args, scope); }; return func(args, songIterator, scope, argErr); } @@ -1605,11 +1536,11 @@ let defineVar = function (identifier, type, goalscope = null) { let opts = { types: [type], scope: goalscope, - returns: Nil + returns: 'Nil' }; define$1(identifier, opts, (args, songIterator, scope, argErr) => { scope.vars.set(identifier, args[0]); - return Nil; + return new PlaybackNilValue(); }); }; /** @@ -1623,8 +1554,8 @@ let defineVar = function (identifier, type, goalscope = null) { let defineBoolean = function (identifier, goalscope = null) { let opts = { types: '*', - scopes: goalscope, - returns: Nil + scope: goalscope, + returns: 'Nil' }; define$1(identifier, opts, (args, songIterator, scope, argErr) => { if (args.length) { @@ -1632,9 +1563,9 @@ let defineBoolean = function (identifier, goalscope = null) { scope.vars.set(identifier, args[0]); } else { - scope.vars.set(identifier, true); + scope.vars.set(identifier, new PlaybackBooleanValue(true)); } - return Nil; + return new PlaybackNilValue; }); }; /*********** ACTUAL FUNCTION DEFINITIONS ***********/ @@ -1647,38 +1578,42 @@ defineVar('playback-version', 'number', 'meta'); define$1('time-signature', { types: ['number', 'number'], scope: 'options', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (!Number.isInteger(Math.log2(args[1]))) { - argErr(`Argument 2 of "time-signature" must be a power of 2 (got ${args}).`); + const value1 = args[0].value; + const value2 = args[1].value; + if (!Number.isInteger(Math.log2(value1))) { + argErr(`Argument 2 of "time-signature" must be a power of 2`); } - scope.vars.set('time-signature', [args[0], args[1]]); - return Nil; + scope.vars.set('time-signature', new PlaybackTimeSignatureValue([value1, value2])); + return new PlaybackNilValue(); }); defineBoolean('swing', 'options'); /*** anywhere but @meta functions ***/ define$1('volume', { types: ['number'], scope: 'no-meta', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (args[0] < 0 || args[0] > 1) { - argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive) (got ${args}).`); + const { value } = args[0]; + if (value < 0 || value > 1) { + argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive)`); } scope.vars.set('volume', args[0]); - return Nil; + return new PlaybackNilValue(); }); defineBoolean('invertible', 'no-meta'); define$1('octave', { types: ['number'], scope: 'no-meta', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { - argErr(`Argument 1 of "octave" must be an integer 0-9 (got ${args}).`); + const { value } = args[0]; + if (!Number.isInteger(value) || value < 0 || value > 9) { + argErr(`Argument 1 of "octave" must be an integer 0-9`); } scope.vars.set('octave', args[0]); - return Nil; + return new PlaybackNilValue(); }); /*** anywhere but config functions (strictly dynamic functions) ***/ define$1('choose', { @@ -1686,24 +1621,24 @@ define$1('choose', { scope: 'no-config', returns: '*' }, (args, songIterator, scope, argErr) => { - let nonNilArgs = args.filter(arg => arg !== Nil); + let nonNilArgs = args.filter(arg => arg.type !== 'Nil'); if (nonNilArgs.length) { let index = Math.floor(Math.random() * nonNilArgs.length); return nonNilArgs[index]; } else { - return Nil; + return new PlaybackNilValue(); } }); let anchorOrNumberToChordAndRoot = function (arg, songIterator) { let anchorChord, root; - if (typeof arg == 'number') { - anchorChord = MelodicBeatLiteral.getAnchorChord(null, songIterator, 1); - root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, arg, 4); + if (arg.type === 'number') { + anchorChord = getAnchorChord(null, songIterator, 1); + root = anchorChordToRoot(anchorChord, arg.value, 4); } - else if (arg.anchor) { - anchorChord = MelodicBeatLiteral.getAnchorChord(arg.anchor, songIterator, 1); - root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, 1, 4); + else { + anchorChord = getAnchorChord(arg.value, songIterator, 1); + root = anchorChordToRoot(anchorChord, 1, 4); } return [anchorChord, root]; }; @@ -1713,34 +1648,34 @@ define$1('progression', { returns: 'boolean' }, (args, songIterator, scope, argErr) => { for (let i in args) { - let arg = args[i]; - let [, goal] = anchorOrNumberToChordAndRoot(arg, songIterator); - if (!goal) { - argErr(`Arguments of "progression" must be numbers or anchors (got "${args}").`); + if (args[0].type !== 'number' && args[0].type !== 'anchor') { + argErr(`Arguments of "progression" must be numbers or anchors`); } - let actualMeasure = songIterator.getRelative(Number(i)); + const [, goal] = anchorOrNumberToChordAndRoot(args[0], songIterator); + const actualMeasure = songIterator.getRelative(Number(i)); if (!actualMeasure) - return false; - let actualChord = MelodicBeatLiteral.normalizeChord(actualMeasure.beats[0].chord); - let actual = MelodicBeatLiteral.anchorChordToRoot(actualChord, 1, 4); + return new PlaybackBooleanValue(false); + const actualChord = normalizeChordForTonal(actualMeasure.beats[0].chord); + const actual = anchorChordToRoot(actualChord, 1, 4); if (actual != goal) - return false; + return new PlaybackBooleanValue(false); } - return true; + return new PlaybackBooleanValue(true); }); define$1('in-scale', { types: '*', scope: 'no-config', returns: 'boolean' }, (args, songIterator, scope, argErr) => { + if ((args[0].type !== 'number' && args[0].type !== 'anchor') + || args[1].type !== 'number' && args[1].type !== 'anchor') { + argErr(`Arguments of "in-scale" must be numbers or anchors`); + } let [, note] = anchorOrNumberToChordAndRoot(args[0], songIterator); let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); - if (!note || !goalChord) { - argErr(`Arguments of "in-scale" must be numbers or anchors (got ${args}).`); - } - let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); + let goalScaleName = chordToScaleName(goalChord); let goalScale = tonal$1.Scale.notes(goalTonic, goalScaleName); - return goalScale.includes(note); + return new PlaybackBooleanValue(goalScale.includes(note)); }); define$1('beat-defined', { types: ['number'], @@ -1749,8 +1684,9 @@ define$1('beat-defined', { }, (args, songIterator, scope, argErr) => { let measure = songIterator.getRelative(0); if (!measure) - return false; - return measure.beats[args[0]].chord !== null; + return new PlaybackBooleanValue(false); + const index = args[0].value; + return new PlaybackBooleanValue(measure.beats[index].chord !== null); }); /*** pattern-only functions ***/ defineBoolean('private', 'pattern'); @@ -1758,13 +1694,13 @@ defineVar('length', 'number', 'pattern'); define$1('chance', { types: ['number'], scope: 'pattern', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if (args[0] < 0 || args[0] > 1) { - argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive) (got ${args}).`); + if (args[0].value < 0 || args[0].value > 1) { + argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive)`); } scope.vars.set('chance', args[0]); - return Nil; + return new PlaybackNilValue(); }); /** @@ -1827,8 +1763,8 @@ class PatternExpressionGroup extends Scope { super(); this.type = 'PatternExpressionGroup'; this.name = '@pattern()'; - this.defaultVars.set('private', false); - this.defaultVars.set('chance', 1); + this.defaultVars.set('private', new PlaybackBooleanValue(false)); + this.defaultVars.set('chance', new PlaybackNumberValue(1)); this.expressions = expressions; this.functionCalls = []; this.nonFunctionCallExpressions = []; @@ -1861,25 +1797,25 @@ class PatternExpressionGroup extends Scope { } execute(songIterator, callerIsTrack = false) { this.inherit(); - let beats = Nil; + let beats = null; for (let function_call of this.functionCalls) { let return_value = function_call.execute(songIterator); if (return_value instanceof NoteSet) { - if (beats !== Nil) { + if (beats) { throw new TooManyBeatsError(this); } beats = return_value; } } - if (callerIsTrack && this.vars.get('private') === true) { - return Nil; // if it's private we can give up now + if (callerIsTrack && this.vars.get('private').value === true) { + return null; // if it's private we can give up now } for (let expression of this.nonFunctionCallExpressions) { if (expression.execute) { expression = expression.execute(songIterator); } if (expression instanceof NoteSet) { - if (beats !== Nil) { + if (beats) { throw new TooManyBeatsError(this); } beats = expression; @@ -1901,7 +1837,7 @@ class PatternStatement extends PatternExpressionGroup { this.condition = (opts.condition !== undefined) ? opts.condition : null; } getChance() { - return this.vars.get('chance'); + return this.vars.get('chance').value; } link(ASTs, parentStyle, parentTrack) { super.link(ASTs, parentStyle, parentTrack); @@ -1923,8 +1859,8 @@ class PatternStatement extends PatternExpressionGroup { else { condition_value = this.condition; } - if (cast_bool(condition_value) === false) - return Nil; + if (condition_value.toBoolean() === false) + return null; } return super.execute(songIterator, callerIsTrack); } @@ -1941,7 +1877,7 @@ class PatternCall { this.pattern; } getChance() { - return this.patternStatement.getChance()(); + return this.patternStatement.getChance(); } init(scope) { this.scope = scope; @@ -2007,7 +1943,7 @@ class JoinedPatternExpression { return (new NoteSet()).concat(...noteSets); } else { - return Nil; + return null; } } } @@ -2017,9 +1953,9 @@ class TrackStatement extends Scope { super(); this.name = opts.identifier; this.type = '@track'; - this.defaultVars.set('octave', 4); - this.defaultVars.set('volume', 1); - this.defaultVars.set('private', false); + this.defaultVars.set('octave', new PlaybackNumberValue(4)); + this.defaultVars.set('volume', new PlaybackNumberValue(1)); + this.defaultVars.set('private', new PlaybackBooleanValue(false)); this.instrument = opts.instrument; this.identifier = opts.identifier; this.members = opts.members; @@ -2069,7 +2005,7 @@ class TrackStatement extends Scope { let result = pattern.execute(songIterator, true); console.log(' - Result:', result); // @TODO: handle multi-measure patterns (via locks?) - if (result !== Nil) { + if (result) { for (let note of result) { if (note.pitch === AwaitingDrum) { throw new DrumBeatInMelodicBeatGroupError(pattern); @@ -2092,8 +2028,8 @@ class TrackStatement extends Scope { return option.noteSet; } } - console.log(' - Final result:', Nil); - return Nil; + console.log(' - Final result:', null); + return null; } } class TrackCall { @@ -2116,8 +2052,8 @@ class GlobalScope extends Scope { } init() { // set some default values - this.vars.set('time-signature', [4, 4]); - this.vars.set('tempo', 120); + this.vars.set('time-signature', new PlaybackTimeSignatureValue([4, 4])); + this.vars.set('tempo', new PlaybackNumberValue(120)); this.tracks = new Map(); this.metaStatements = []; // @TODO: stop circular dependencies? cache them and mark one as mom @@ -2167,7 +2103,7 @@ class GlobalScope extends Scope { let trackNoteMap = new Map(); for (let [, track] of this.tracks) { let trackNotes = track.execute(songIterator); - if (trackNotes !== Nil) + if (trackNotes) trackNoteMap.set(track.instrument, trackNotes); } return trackNoteMap; @@ -2181,11 +2117,6 @@ class GlobalScope extends Scope { } } -class AnchorArgument { - constructor(anchor) { - this.anchor = anchor; - } -} class BooleanOperator { constructor(...args) { this.args = args; @@ -2220,7 +2151,7 @@ class BooleanNot extends BooleanOperator { } execute(songIterator) { let args = this.resolve_args(songIterator); - return !cast_bool(args[0]); + return new PlaybackBooleanValue(!args[0].toBoolean()); } } class BooleanAnd extends BooleanOperator { @@ -2231,7 +2162,7 @@ class BooleanAnd extends BooleanOperator { // sorry no short-circuiting because this code is prettier // @TODO: add short-circuiting if this actually makes it too slow let args = this.resolve_args(songIterator); - return cast_bool(args[0]) && cast_bool(args[1]); + return new PlaybackBooleanValue(args[0].toBoolean() && args[1].toBoolean()); } } class BooleanOr extends BooleanOperator { @@ -2240,7 +2171,150 @@ class BooleanOr extends BooleanOperator { } execute(songIterator) { let args = this.resolve_args(songIterator); - return cast_bool(args[0]) || cast_bool(args[1]); + return new PlaybackBooleanValue(args[0].toBoolean() || args[1].toBoolean()); + } +} + +class MelodicBeatLiteral { + constructor(opts) { + this.value = new PlaybackMelodicBeatValue(opts.time, opts.pitch, opts.octave); + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + if (this.value.time.time === 'auto') { + return this.indexInMeasure + 1; + } + else { + return this.value.time.time; + } + } + handleInversion(songIterator, pitches) { + let tonicPC = songIterator.song.getTransposedKey(); + let tonicNote = tonal$1.Note.from({ oct: this.getOctave() }, tonicPC); + let tonic = tonal$1.Note.midi(tonicNote); + let outPitches = []; + for (let pitchNote of pitches) { + let pitch = tonal$1.Note.midi(pitchNote); + if (pitch - tonic >= 6) + pitch -= 12; + outPitches.push(tonal$1.Note.fromMidi(pitch)); + } + return outPitches; + } + getAnchorData(songIterator) { + let anchorChord = getAnchorChord(this.value.pitch.anchor, songIterator, this.getTime()); + let root = anchorChordToRoot(anchorChord, this.value.pitch.degree, this.getOctave()); + return [anchorChord, root]; + } + getPitches(songIterator) { + let [anchorChord, root] = this.getAnchorData(songIterator); + let pitches; + if (this.value.pitch.chord) { + // this feels extremely incorrect + // why would anyone need it to work this way + let anchorChordType = tonal$1.Chord.tokenize(anchorChord)[1]; + pitches = tonal$1.Chord.notes(root, anchorChordType); + } + else { + pitches = [root]; + } + if (this.scope.vars.get('invertible')) { + pitches = this.handleInversion(songIterator, pitches); + } + return pitches; + } + /** + * Returns true if the beat is anchored via STEP or ARPEGGIATE + * @returns {boolean} + */ + isDynamic() { + return ['STEP', 'ARPEGGIATE'].includes(this.value.pitch.anchor); + } + getOctave() { + if (this.value.octave === 'inherit') { + return this.scope.vars.get('octave').value; + } + else { + return this.value.octave; + } + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + if (this.value.time.flag === 'STACCATO') { + return Math.min(0.25, duration); + } + else { + return duration; + } + } + getVolume() { + let volume = this.scope.vars.get('volume').value; + if (this.value.time.flag === 'ACCENTED') + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let notes = new NoteSet(); + let time = this.getTime(); // @TODO: this varies with rolling + let pitches = this.getPitches(songIterator); + let duration = this.getDuration(); // @TODO: this varies with rolling + let volume = this.getVolume(); + for (let pitch of pitches) { + notes.push(new Note({ + time: time, + pitch: pitch, + duration: duration, + volume: volume + })); + } + return notes; + } +} +class DrumBeatLiteral { + constructor(opts) { + this.value = new PlaybackDrumBeatValue(opts.time, opts.accented); + this.scope = null; + this.parentMeasure = null; + this.indexInMeasure = null; + } + init(scope, parentMeasure, indexInMeasure) { + this.scope = scope; + this.parentMeasure = parentMeasure; + this.indexInMeasure = indexInMeasure; + } + getTime() { + return this.value.time; + } + getDuration() { + let duration; + duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); + return duration; + } + getVolume() { + let volume = this.scope.vars.get('volume').value; + if (this.value.accented) + volume = Math.min(1, volume += .1); + return volume; + } + execute(songIterator) { + let time = this.getTime(); + let duration = this.getDuration(); + let volume = this.getVolume(); + return new NoteSet(new Note({ + time: time, + pitch: AwaitingDrum, + duration: duration, + volume: volume + })); } } @@ -2259,8 +2333,8 @@ class BeatGroupLiteral { for (let i = 0; i < this.measures.length; i++) { let offset = i * 4; // @TODO: pull in actual meter somehow let measureNotes = this.measures[i].execute(songIterator); - if (measureNotes === Nil) - return Nil; // lets a/s abort the beatgroup + if (measureNotes === null) + return null; // lets a/s abort the beatgroup for (let measureNote of measureNotes) { measureNote.time += offset; joinedMeasures.push(measureNote); @@ -2285,7 +2359,7 @@ class BeatGroupLiteral { // later if it's a multi-measure beatgroup) // @TODO: wtf? const nextMeasure = songIterator.getRelative(1); - return MelodicBeatLiteral.normalizeChord(nextMeasure && nextMeasure.beats[0].chord); + return normalizeChordForTonal(nextMeasure && nextMeasure.beats[0].chord); } } class Measure { @@ -2330,8 +2404,8 @@ class Measure { let joined = new NoteSet(); for (let beat of this.beats) { let notes = beat.execute(songIterator); - if (notes === Nil) - return Nil; // lets a and s abort the beatgroup. + if (!notes) + return null; // lets a and s abort the beatgroup. joined.push(...notes); } return joined; @@ -2431,11 +2505,11 @@ let ParserRules = [ {"name": "FunctionCallExpression$macrocall$1", "symbols": ["FunctionCallExpression$macrocall$2", "FunctionCallExpression$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, "_?", "FunctionCallExpression$macrocall$1", "_?", {"literal":")"}], "postprocess": d => new FunctionCall(d[0], d[4])}, {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, {"literal":")"}], "postprocess": d => new FunctionCall(d[0], [])}, - {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": d => new PlaybackNumberValue(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": d => new PlaybackStringValue(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": d => new PlaybackBooleanValue(d[0])}, {"name": "FunctionCallArgument", "symbols": ["PatternExpression"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new AnchorArgument(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new PlaybackAnchorValue(d[0])}, {"name": "FunctionCallArgument", "symbols": [{"literal":"not"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanNot(d[2])}, {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"and"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanAnd(d[0], d[4])}, {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"or"}, "_", "FunctionCallArgument"], "postprocess": d => new BooleanOr(d[0], d[4])}, diff --git a/src/ast/ArgumentOperators.ts b/src/ast/ArgumentOperators.ts index 5ba64dd..15d2725 100644 --- a/src/ast/ArgumentOperators.ts +++ b/src/ast/ArgumentOperators.ts @@ -1,16 +1,7 @@ -import {Nil, cast_bool} from './type_utils'; import Scope from './Scope'; +import * as values from '../values/values'; import SongIterator from 'notochord-song/types/songiterator'; -type Anchor = 'KEY' | 'NEXT' | 'STEP' | 'ARPEGGIATE'; -export class AnchorArgument { - public anchor: Anchor; - - constructor(anchor: Anchor) { - this.anchor = anchor; - } -} - class BooleanOperator { public args: any[]; public scope: Scope; @@ -29,7 +20,7 @@ class BooleanOperator { if(arg.init) arg.init(scope); }); } - resolve_args(songIterator: SongIterator) { + resolve_args(songIterator: SongIterator): values.PlaybackValue[] { return this.args.map(arg => { if(arg.execute) { return arg.execute(songIterator); @@ -46,7 +37,7 @@ export class BooleanNot extends BooleanOperator { } execute(songIterator: SongIterator) { let args = this.resolve_args(songIterator); - return !cast_bool(args[0]); + return new values.PlaybackBooleanValue(!args[0].toBoolean()); } } export class BooleanAnd extends BooleanOperator { @@ -57,7 +48,7 @@ export class BooleanAnd extends BooleanOperator { // sorry no short-circuiting because this code is prettier // @TODO: add short-circuiting if this actually makes it too slow let args = this.resolve_args(songIterator); - return cast_bool(args[0]) && cast_bool(args[1]); + return new values.PlaybackBooleanValue(args[0].toBoolean() && args[1].toBoolean()); } } export class BooleanOr extends BooleanOperator { @@ -66,6 +57,6 @@ export class BooleanOr extends BooleanOperator { } execute(songIterator: SongIterator) { let args = this.resolve_args(songIterator); - return cast_bool(args[0]) || cast_bool(args[1]); + return new values.PlaybackBooleanValue(args[0].toBoolean() || args[1].toBoolean()); } } diff --git a/src/ast/BeatGroups.ts b/src/ast/BeatGroups.ts index 5545f21..ad832b3 100644 --- a/src/ast/BeatGroups.ts +++ b/src/ast/BeatGroups.ts @@ -1,12 +1,12 @@ import { MelodicBeatInDrumBeatGroupError } from './errors'; -import {Nil} from './type_utils'; import {AwaitingDrum, Note, NoteSet} from '../MIDI/Note'; import {MelodicBeatLiteral} from './BeatLiterals'; import FunctionCall from './FunctionCall'; import Scope from './Scope'; import SongIterator from 'notochord-song/types/songiterator'; +import { normalizeChordForTonal } from './music_utils'; export class BeatGroupLiteral { public measures: Measure[]; @@ -22,12 +22,12 @@ export class BeatGroupLiteral { this.measures.forEach((measure, i) => measure.init(scope, this, i)); } link() {return;} - execute(songIterator) { + execute(songIterator: SongIterator): NoteSet | null { let joinedMeasures = new NoteSet(); for(let i = 0; i < this.measures.length; i++) { let offset = i * 4; // @TODO: pull in actual meter somehow let measureNotes = this.measures[i].execute(songIterator); - if(measureNotes === Nil) return Nil; // lets a/s abort the beatgroup + if(measureNotes === null) return null; // lets a/s abort the beatgroup for(let measureNote of measureNotes as NoteSet) { measureNote.time += offset; joinedMeasures.push(measureNote); @@ -52,7 +52,7 @@ export class BeatGroupLiteral { // later if it's a multi-measure beatgroup) // @TODO: wtf? const nextMeasure = songIterator.getRelative(1); - return MelodicBeatLiteral.normalizeChord(nextMeasure && nextMeasure.beats[0].chord); + return normalizeChordForTonal(nextMeasure && nextMeasure.beats[0].chord); } } @@ -107,7 +107,7 @@ export class Measure { let joined = new NoteSet(); for(let beat of this.beats) { let notes = beat.execute(songIterator); - if(notes === Nil) return Nil; // lets a and s abort the beatgroup. + if(!notes) return null; // lets a and s abort the beatgroup. joined.push(...notes); } return joined; diff --git a/src/ast/BeatLiterals.ts b/src/ast/BeatLiterals.ts index 6209cee..56cfc09 100644 --- a/src/ast/BeatLiterals.ts +++ b/src/ast/BeatLiterals.ts @@ -1,83 +1,38 @@ -//import {Nil} from './type_utils.js'; import tonal from '../lib/tonal.min.js'; import {AwaitingDrum, Note, NoteSet} from '../MIDI/Note'; import Scope from './Scope'; import { Measure } from './BeatGroups'; +import { getAnchorChord, anchorChordToRoot } from './music_utils'; +import { PlaybackMelodicBeatValue, PlaybackDrumBeatValue } from '../values/values'; import SongIterator from 'notochord-song/types/songiterator'; -type TimePart = { - time: 'auto' | number; - flag?: 'STACCATO' | 'ACCENTED' -}; -type PitchPart = { - degree: number; - anchor?: 'KEY' | 'NEXT' | 'STEP' | 'ARPEGGIATE'; - roll?: 'ROLL_UP' | 'ROLL_DOWN'; - chord: boolean; // actually undefined | true but ts doesn't need to know that -}; - export class MelodicBeatLiteral { - public time: TimePart; - public pitch: PitchPart; - public octave: number | 'inherit'; + public value: PlaybackMelodicBeatValue; public scope: Scope; public parentMeasure: Measure; public indexInMeasure: number; public cachedAnchor: any; constructor(opts) { - this.time = opts.time || {time: 'auto'}; - this.pitch = opts.pitch; - this.octave = opts.octave || 'inherit'; + this.value = new PlaybackMelodicBeatValue(opts.time, opts.pitch, opts.octave); this.scope = null; this.parentMeasure = null; this.indexInMeasure = null; this.cachedAnchor = null; // used for STEP/ARPEGGIATE interpolation } - init(scope, parentMeasure, indexInMeasure) { + init(scope: Scope, parentMeasure: Measure, indexInMeasure: number) { this.scope = scope; this.parentMeasure = parentMeasure; this.indexInMeasure = indexInMeasure; } getTime() { - if(this.time.time === 'auto') { + if(this.value.time.time === 'auto') { return this.indexInMeasure + 1; } else { - return this.time.time; + return this.value.time.time; } } - /** - * Normalize a chord into a form tonal can handle - * @param {string} [chord=''] - * @return {string} - */ - static normalizeChord(chord = '') { - return chord - .replace(/-/g, '_') // tonal uses _ over - for minor7 - .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? - } - static chordToScaleName(chord) { - let chordType = tonal.Chord.tokenize(chord)[1]; - - // @TODO: make this more robust - let names = tonal.Chord.props(chordType).names; - if(names.includes('dim')) return 'diminished'; - if(names.includes('aug')) return 'augmented'; - if(names.includes('Major')) return 'major'; - if(names.includes('minor')) return 'minor'; - if(names.includes('minor7')) return 'dorian'; - if(names.includes('Dominant')) return 'mixolydian'; - // if none of the above match, do our best to find the closest fit - let closestScale = 'major' - names.forEach(name => { - if(name.startsWith('dim')) closestScale = 'diminished'; - if(name.startsWith('aug')) closestScale = 'augmented'; - if(name.startsWith('M')) closestScale = 'major'; - if(name.startsWith('m')) closestScale = 'minor'; - }); - return closestScale; - } - handleInversion(songIterator, pitches) { + handleInversion(songIterator: SongIterator, pitches: string[]) { let tonicPC = songIterator.song.getTransposedKey(); let tonicNote = tonal.Note.from({oct: this.getOctave()}, tonicPC); let tonic = tonal.Note.midi(tonicNote); @@ -89,67 +44,21 @@ export class MelodicBeatLiteral { } return outPitches; } - static getAnchorChord(anchor, songIterator: SongIterator, currentTime) { - let anchorChord; - switch(anchor) { - case 'KEY': { - anchorChord = songIterator.song.getTransposedKey(); - } - case 'NEXT': { - let nextMeasure = songIterator.getRelative(1); - if(nextMeasure) { - anchorChord = nextMeasure.beats[0].chord; - } else { - anchorChord = songIterator.song.getTransposedKey(); - } - } - case 'STEP': - case 'ARPEGGIATE': { - /* - let prev = songIterator.getRelative(0)[0]; //??? - if(!this.parentMeasure) console.log('tttttttt', this); - let next = this.parentMeasure.getNextStaticBeatRoot( - this.indexInMeasure, - songIterator - );*/ - - } - default: { - // crawl backward through this measure to get the last set beat - let lastSetBeat = Math.floor(currentTime); - let iteratorMeasure = songIterator.getRelative(0); - if(!iteratorMeasure) break; - do { - const beat = iteratorMeasure.beats[lastSetBeat] - anchorChord = beat && beat.chord; - lastSetBeat--; - } while(!anchorChord); - } - } - return this.normalizeChord(anchorChord); - } - static anchorChordToRoot(anchorChord, degree, octave) { - let anchorTonic = tonal.Chord.tokenize(anchorChord)[0]; - let anchorScaleName = this.chordToScaleName(anchorChord); - let scalePCs = tonal.Scale.notes(anchorTonic, anchorScaleName); - let rootPC = scalePCs[degree - 1]; - return tonal.Note.from({oct: octave}, rootPC); - } - getAnchorData(songIterator) { - let anchorChord = MelodicBeatLiteral.getAnchorChord( - this.pitch.anchor, songIterator, this.getTime() + getAnchorData(songIterator: SongIterator) { + let anchorChord = getAnchorChord( + this.value.pitch.anchor, songIterator, this.getTime() ); - let root = MelodicBeatLiteral.anchorChordToRoot( - anchorChord, this.pitch.degree, this.getOctave() + let root = anchorChordToRoot( + anchorChord, this.value.pitch.degree, this.getOctave() ); return [anchorChord, root]; } getPitches(songIterator: SongIterator) { let [anchorChord, root] = this.getAnchorData(songIterator); - let pitches; - if(this.pitch.chord) { + let pitches: string[]; + if(this.value.pitch.chord) { // this feels extremely incorrect // why would anyone need it to work this way let anchorChordType = tonal.Chord.tokenize(anchorChord)[1]; @@ -169,30 +78,30 @@ export class MelodicBeatLiteral { * @returns {boolean} */ isDynamic() { - return ['STEP', 'ARPEGGIATE'].includes(this.pitch.anchor); + return ['STEP', 'ARPEGGIATE'].includes(this.value.pitch.anchor); } getOctave() { - if(this.octave === 'inherit') { - return this.scope.vars.get('octave'); + if(this.value.octave === 'inherit') { + return this.scope.vars.get('octave').value as number; } else { - return this.octave; + return this.value.octave; } } getDuration() { let duration; duration = this.parentMeasure.calculateDurationAfter(this.indexInMeasure); - if(this.time.flag === 'STACCATO') { + if(this.value.time.flag === 'STACCATO') { return Math.min(0.25, duration); } else { return duration; } } getVolume() { - let volume = this.scope.vars.get('volume'); - if(this.time.flag === 'ACCENTED') volume = Math.min(1, volume += .1); + let volume = this.scope.vars.get('volume').value as number; + if(this.value.time.flag === 'ACCENTED') volume = Math.min(1, volume += .1); return volume; } - execute(songIterator) { + execute(songIterator: SongIterator) { let notes = new NoteSet(); let time = this.getTime(); // @TODO: this varies with rolling let pitches = this.getPitches(songIterator); @@ -213,26 +122,24 @@ export class MelodicBeatLiteral { } export class DrumBeatLiteral { - public time: number; - public accented: boolean; + public value: PlaybackDrumBeatValue; public scope: Scope; public parentMeasure: Measure; public indexInMeasure: number; constructor(opts) { - this.time = opts.time; - this.accented = opts.accented || false; + this.value = new PlaybackDrumBeatValue(opts.time, opts.accented); this.scope = null; this.parentMeasure = null; this.indexInMeasure = null; } - init(scope, parentMeasure, indexInMeasure) { + init(scope: Scope, parentMeasure: Measure, indexInMeasure: number) { this.scope = scope; this.parentMeasure = parentMeasure; this.indexInMeasure = indexInMeasure; } getTime() { - return this.time; + return this.value.time; } getDuration() { let duration; @@ -240,8 +147,8 @@ export class DrumBeatLiteral { return duration; } getVolume() { - let volume = this.scope.vars.get('volume'); - if(this.accented) volume = Math.min(1, volume += .1); + let volume = this.scope.vars.get('volume').value as number; + if(this.value.accented) volume = Math.min(1, volume += .1); return volume; } execute(songIterator) { diff --git a/src/ast/FunctionCall.ts b/src/ast/FunctionCall.ts index 80928a0..98db3d4 100644 --- a/src/ast/FunctionCall.ts +++ b/src/ast/FunctionCall.ts @@ -1,15 +1,9 @@ import * as function_data from './function_data'; import {FunctionNameError} from './errors'; import SongIterator from 'notochord-song/types/songiterator'; +import * as values from '../values/values'; import Scope from './Scope'; -type FunctionDefinition = { - types: (Function|string)[] | '*'; - scope: 'meta' | 'options' | 'no-config' | 'pattern' | 'no-meta'; - returns: string | Function | symbol; - execute: (args: any[], songIterator: SongIterator, scope: Scope) => any; -}; - /** * If the value is a FunctionCall, call it and return the returned value. * Otherwise, return the value itself. @@ -17,7 +11,7 @@ type FunctionDefinition = { */ // @TODO: if this is needed elsewhere, put it somewhere useful. export default class FunctionCall { public identifier: string; - public definition: FunctionDefinition; + public definition: function_data.IFunctionDefinition; public args: any[]; public scope: Scope; public returns: string | Function | symbol; @@ -27,7 +21,7 @@ export default class FunctionCall { * @param {string} identifier The name of the function. Ideally it should * match the name of one of the functions in function_data.js */ - constructor(identifier, args) { + constructor(identifier: string, args: values.PlaybackValue[]) { this.identifier = identifier; this.definition = function_data.definitions.get(identifier); this.args = args; diff --git a/src/ast/GlobalScope.ts b/src/ast/GlobalScope.ts index 6dc2c4e..6c03ae7 100644 --- a/src/ast/GlobalScope.ts +++ b/src/ast/GlobalScope.ts @@ -1,9 +1,9 @@ -import {Nil} from './type_utils'; import {NoteSet} from '../MIDI/Note'; import {NoSuchStyleError, NoSuchTrackError} from './errors'; import Scope from './Scope'; import {MetaStatement, OptionsStatement, ImportStatement} from './ConfigStatements'; import {TrackStatement, TrackCall} from './Track'; +import * as values from '../values/values'; import SongIterator from 'notochord-song/types/songiterator'; type Statement = MetaStatement | OptionsStatement | ImportStatement | TrackStatement | TrackCall; @@ -28,8 +28,8 @@ export default class GlobalScope extends Scope { init() { // set some default values - this.vars.set('time-signature', [4, 4]); - this.vars.set('tempo', 120); + this.vars.set('time-signature', new values.PlaybackTimeSignatureValue([4, 4])); + this.vars.set('tempo', new values.PlaybackNumberValue(120)); this.tracks = new Map(); this.metaStatements = []; @@ -83,7 +83,7 @@ export default class GlobalScope extends Scope { let trackNoteMap = new Map(); for(let [, track] of this.tracks) { let trackNotes = track.execute(songIterator); - if(trackNotes !== Nil) trackNoteMap.set(track.instrument, trackNotes); + if(trackNotes) trackNoteMap.set(track.instrument, trackNotes); } return trackNoteMap; } diff --git a/src/ast/Pattern.ts b/src/ast/Pattern.ts index 6181e89..a8c82ae 100644 --- a/src/ast/Pattern.ts +++ b/src/ast/Pattern.ts @@ -1,4 +1,3 @@ -import {Nil, cast_bool} from './type_utils'; import {NoteSet} from '../MIDI/Note'; import { TooManyBeatsError, @@ -8,6 +7,7 @@ import { } from './errors.js'; import Scope from './Scope.js'; import FunctionCall from './FunctionCall.js'; +import * as values from '../values/values'; import SongIterator from 'notochord-song/types/songiterator'; export class PatternExpressionGroup extends Scope { @@ -21,8 +21,8 @@ export class PatternExpressionGroup extends Scope { this.type = 'PatternExpressionGroup'; this.name = '@pattern()'; - this.defaultVars.set('private', false); - this.defaultVars.set('chance', 1); + this.defaultVars.set('private', new values.PlaybackBooleanValue(false)); + this.defaultVars.set('chance', new values.PlaybackNumberValue(1)); this.expressions = expressions; this.functionCalls = []; @@ -52,27 +52,27 @@ export class PatternExpressionGroup extends Scope { expression.link(ASTs, parentStyle, parentTrack); }); } - execute(songIterator, callerIsTrack = false) { + execute(songIterator: SongIterator, callerIsTrack = false): NoteSet | null { this.inherit(); - let beats: NoteSet | symbol = Nil; + let beats: NoteSet = null; for(let function_call of this.functionCalls) { let return_value = function_call.execute(songIterator); if(return_value instanceof NoteSet) { - if(beats !== Nil) { + if(beats) { throw new TooManyBeatsError(this); } beats = return_value; } } - if(callerIsTrack && this.vars.get('private') === true) { - return Nil; // if it's private we can give up now + if(callerIsTrack && this.vars.get('private').value === true) { + return null; // if it's private we can give up now } for(let expression of this.nonFunctionCallExpressions) { if(expression.execute) { expression = expression.execute(songIterator); } if(expression instanceof NoteSet) { - if(beats !== Nil) { + if(beats) { throw new TooManyBeatsError(this); } beats = expression; @@ -97,7 +97,7 @@ export class PatternStatement extends PatternExpressionGroup { this.condition = (opts.condition !== undefined) ? opts.condition : null; } getChance() { - return this.vars.get('chance'); + return this.vars.get('chance').value as number; } link(ASTs, parentStyle, parentTrack) { super.link(ASTs, parentStyle, parentTrack); @@ -117,7 +117,7 @@ export class PatternStatement extends PatternExpressionGroup { } else { condition_value = this.condition; } - if(cast_bool(condition_value) === false) return Nil; + if((condition_value as values.PlaybackValue).toBoolean() === false) return null; } return super.execute(songIterator, callerIsTrack); } @@ -142,7 +142,7 @@ export class PatternCall { this.pattern; } getChance() { - return this.patternStatement.getChance()(); + return this.patternStatement.getChance(); } init(scope) { this.scope = scope; @@ -212,7 +212,7 @@ export class JoinedPatternExpression { if(noteSets.length) { return (new NoteSet()).concat(...noteSets); } else { - return Nil; + return null; } } } diff --git a/src/ast/Scope.ts b/src/ast/Scope.ts index 80dc631..0b95fab 100644 --- a/src/ast/Scope.ts +++ b/src/ast/Scope.ts @@ -1,10 +1,12 @@ +import { PlaybackValue } from '../values/values'; + /* * In Playback styles, basically any pair of curly brackets defines a scope * which inherits settings from its parent scope but can overwrite them. */ export default class Scope { - public defaultVars: Map; - public vars: Map; + public defaultVars: Map; + public vars: Map; public name: string; public type: string; public scope: Scope; diff --git a/src/ast/Track.ts b/src/ast/Track.ts index 70bc495..12dbfbd 100644 --- a/src/ast/Track.ts +++ b/src/ast/Track.ts @@ -1,4 +1,3 @@ -import {Nil} from './type_utils'; import { DrumBeatInMelodicBeatGroupError } from './errors.js'; @@ -7,6 +6,7 @@ import Scope from './Scope'; import FunctionCall from './FunctionCall'; import {PatternStatement, PatternCall} from './Pattern'; import SongIterator from 'notochord-song/types/songiterator'; +import * as values from '../values/values'; import {NoteSet} from '../MIDI/Note'; export class TrackStatement extends Scope { @@ -23,9 +23,9 @@ export class TrackStatement extends Scope { this.name = opts.identifier; this.type = '@track'; - this.defaultVars.set('octave', 4); - this.defaultVars.set('volume', 1); - this.defaultVars.set('private', false); + this.defaultVars.set('octave', new values.PlaybackNumberValue(4)); + this.defaultVars.set('volume', new values.PlaybackNumberValue(1)); + this.defaultVars.set('private', new values.PlaybackBooleanValue(false)); this.instrument = opts.instrument; this.identifier = opts.identifier; @@ -77,7 +77,7 @@ export class TrackStatement extends Scope { let result = pattern.execute(songIterator, true); console.log(' - Result:', result); // @TODO: handle multi-measure patterns (via locks?) - if(result !== Nil) { + if(result) { for(let note of (result as NoteSet)) { if (note.pitch === AwaitingDrum) { throw new DrumBeatInMelodicBeatGroupError(pattern); @@ -101,8 +101,8 @@ export class TrackStatement extends Scope { return option.noteSet; } } - console.log(' - Final result:', Nil); - return Nil; + console.log(' - Final result:', null); + return null; } } export class TrackCall { diff --git a/src/ast/ast_nodes.ts b/src/ast/ast_nodes.ts index ce01106..1c4dc2c 100644 --- a/src/ast/ast_nodes.ts +++ b/src/ast/ast_nodes.ts @@ -11,7 +11,7 @@ import {MetaStatement, OptionsStatement, ImportStatement} from './ConfigStatemen import {TrackStatement, TrackCall} from './Track.js'; import {PatternStatement, PatternExpressionGroup, PatternCall, JoinedPatternExpression} from './Pattern.js'; import FunctionCall from './FunctionCall.js'; -import {AnchorArgument, BooleanNot, BooleanAnd, BooleanOr} from './ArgumentOperators.js'; +import {BooleanNot, BooleanAnd, BooleanOr} from './ArgumentOperators.js'; import {BeatGroupLiteral, Measure, DrumBeatGroupLiteral} from './BeatGroups.js'; import {MelodicBeatLiteral, DrumBeatLiteral} from './BeatLiterals.js'; @@ -28,7 +28,7 @@ export { /* functions */ FunctionCall, - AnchorArgument, BooleanNot, BooleanAnd, BooleanOr, + BooleanNot, BooleanAnd, BooleanOr, /* beat groups */ BeatGroupLiteral, Measure, DrumBeatGroupLiteral, diff --git a/src/ast/errors.ts b/src/ast/errors.ts index c48d754..44ff309 100644 --- a/src/ast/errors.ts +++ b/src/ast/errors.ts @@ -1,3 +1,5 @@ +import { PlaybackValue } from '../values/values'; + // does this have to be an Error? idc class PlaybackError extends Error { constructor(message, scope) { @@ -43,8 +45,8 @@ export class FunctionScopeError extends PlaybackError { } } export class FunctionArgumentsError extends PlaybackError { - constructor(message, scope) { - super(message, scope); + constructor(message: string, args: PlaybackValue[], scope) { + super(`${message} (got ${args.map(a => a.toOutputString()).join(', ')})`, scope); } } diff --git a/src/ast/function_data.ts b/src/ast/function_data.ts index 6a3051c..4000864 100644 --- a/src/ast/function_data.ts +++ b/src/ast/function_data.ts @@ -1,14 +1,28 @@ import tonal from '../lib/tonal.min.js'; +import { normalizeChordForTonal, getAnchorChord, anchorChordToRoot, chordToScaleName } from './music_utils'; import {MelodicBeatLiteral} from './BeatLiterals'; +import * as values from '../values/values'; import {FunctionArgumentsError, FunctionScopeError} from './errors'; import FunctionCall from './FunctionCall'; -import {Nil} from './type_utils'; import SongIterator from 'notochord-song/types/songiterator'; import Scope from './Scope'; -let definitions = new Map(); +interface IDefineOpts { + types?: ArgType[] | '*'; + scope?: GoalScope; + returns: ArgType; +} + +export interface IFunctionDefinition { + types?: ArgType[] | '*'; + scope?: GoalScope; + returns: ArgType; + execute: (args: values.PlaybackValue[], songIterator: SongIterator, scope: Scope) => values.PlaybackValue; +} + +let definitions = new Map(); -type ArgType = '*' | 'string' | 'number' | 'boolean' | ((...args: any[]) => void) | Nil; +type ArgType = values.PlaybackValue['type'] | '*'; /** * Make an assertion about argument count and types. @@ -18,36 +32,25 @@ type ArgType = '*' | 'string' | 'number' | 'boolean' | ((...args: any[]) => void * (instanceof) to expect. * @param {Scope} scope The scope, for error logging. */ -export function assertArgTypes(identifier: string, args, types: ArgType[] | '*', scope: Scope) { +export function assertArgTypes(identifier: string, args: values.PlaybackValue[], types: ArgType[] | '*', scope: Scope) { if(types == '*') return; if(args.length != types.length) { - throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, scope); + throw new FunctionArgumentsError(`"${identifier}" requires ${types.length} arguments.`, args, scope); } for(let i in args) { if(types[i] == '*') continue; let arg = args[i]; if(arg instanceof FunctionCall) { - arg = arg.returns; - if(arg == '*') { + if(arg.returns == '*') { continue; // what's the correct functionality here? cry? - } else if(typeof types[i] == 'string') { - if(arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i)+1} of "${identifier}" must be a ${types[i]}.`, scope); - } } else { - if(arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i)+1} of "${identifier}" must be a ${types[i].name}.`, scope); + if(arg.returns !== types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i)+1} of "${identifier}" must be a ${types[i]}.`, args, scope); } } } else { - if(typeof types[i] == 'string') { - if(typeof arg != types[i]) { - throw new FunctionArgumentsError(`Argument ${Number(i)+1} of "${identifier}" must be a ${types[i]}.`, scope); - } - } else { - if(!(arg instanceof types[i])) { - throw new FunctionArgumentsError(`Argument ${Number(i)+1} of "${identifier}" must be a ${types[i].name}.`, scope); - } + if(arg.type !== types[i]) { + throw new FunctionArgumentsError(`Argument ${Number(i)+1} of "${identifier}" must be a ${types[i]}.`, args, scope); } } } @@ -94,12 +97,6 @@ export function assertScope(identifier: string, goalscope: GoalScope = 'no-meta' } } -interface IDefineOpts { - types?: ArgType | ArgType[]; - scope?: GoalScope; - returns: ArgType; -} - /** * Define a function. * @param {string} identifier The name of the function. @@ -119,14 +116,14 @@ interface IDefineOpts { * - argErr: a function. If the function does further testing on its * arguments and there's an issue, pass this the error message and it throws. */ -let define = function(identifier: string, opts: IDefineOpts, func: (args: any[], songIterator: SongIterator, scope: Scope, argErr: (message: string) => void) => any) { +let define = function(identifier: string, opts: IDefineOpts, func: (args: values.PlaybackValue[], songIterator: SongIterator, scope: Scope, argErr: (message: string) => void) => values.PlaybackValue) { let definition = { types: opts.types || '*', returns: opts.returns || '*', scope: opts.scope || 'no-meta', - execute: (args: any[], songIterator: SongIterator, scope: Scope) => { + execute: (args: values.PlaybackValue[], songIterator: SongIterator, scope: Scope) => { let argErr = message => { - throw new FunctionArgumentsError(message, scope); + throw new FunctionArgumentsError(message, args, scope); }; return func(args, songIterator, scope, argErr); } @@ -148,11 +145,11 @@ let defineVar = function(identifier, type, goalscope = null) { let opts: IDefineOpts = { types: [type], scope: goalscope, - returns: Nil + returns: 'Nil' }; define(identifier, opts, (args, songIterator, scope, argErr) => { scope.vars.set(identifier, args[0]); - return Nil; + return new values.PlaybackNilValue(); }) } @@ -168,16 +165,16 @@ let defineBoolean = function(identifier: string, goalscope = null) { let opts: IDefineOpts = { types: '*', scope: goalscope, - returns: Nil + returns: 'Nil' } define(identifier, opts, (args, songIterator, scope, argErr) => { if(args.length) { assertArgTypes(identifier, args, ['boolean'], scope); scope.vars.set(identifier, args[0]); } else { - scope.vars.set(identifier, true); + scope.vars.set(identifier, new values.PlaybackBooleanValue(true)); } - return Nil; + return new values.PlaybackNilValue; }) } @@ -194,14 +191,16 @@ define('time-signature', { types: ['number', 'number'], scope: 'options', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if(!Number.isInteger(Math.log2(args[1]))) { - argErr(`Argument 2 of "time-signature" must be a power of 2 (got ${args}).`); + const value1 = (args[0] as values.PlaybackNumberValue).value; + const value2 = (args[1] as values.PlaybackNumberValue).value; + if(!Number.isInteger(Math.log2(value1))) { + argErr(`Argument 2 of "time-signature" must be a power of 2`); } - scope.vars.set('time-signature', [args[0], args[1]]); - return Nil; + scope.vars.set('time-signature', new values.PlaybackTimeSignatureValue([value1, value2])); + return new values.PlaybackNilValue(); }); defineBoolean('swing', 'options'); @@ -210,28 +209,30 @@ define('volume', { types: ['number'], scope: 'no-meta', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if(args[0] < 0 || args[0] > 1) { - argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive) (got ${args}).`); + const { value } = (args[0] as values.PlaybackNumberValue); + if(value < 0 || value > 1) { + argErr(`Argument 1 of "volume" must be in range 0-1 (inclusive)`); } scope.vars.set('volume', args[0]); - return Nil; + return new values.PlaybackNilValue(); }); defineBoolean('invertible', 'no-meta'); define('octave', { types: ['number'], scope: 'no-meta', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if(!Number.isInteger(args[0]) || args[0] < 0 || args[0] > 9) { - argErr(`Argument 1 of "octave" must be an integer 0-9 (got ${args}).`); + const { value } = (args[0] as values.PlaybackNumberValue); + if(!Number.isInteger(value) || value < 0 || value > 9) { + argErr(`Argument 1 of "octave" must be an integer 0-9`); } scope.vars.set('octave', args[0]); - return Nil; + return new values.PlaybackNilValue(); }); /*** anywhere but config functions (strictly dynamic functions) ***/ @@ -242,25 +243,25 @@ define('choose', returns: '*' }, (args, songIterator, scope, argErr) => { - let nonNilArgs = args.filter(arg => arg !== Nil); + let nonNilArgs = args.filter(arg => arg.type !== 'Nil'); if(nonNilArgs.length) { let index = Math.floor(Math.random() * nonNilArgs.length); return nonNilArgs[index]; } else { - return Nil; + return new values.PlaybackNilValue(); } }); -let anchorOrNumberToChordAndRoot = function(arg, songIterator) { +let anchorOrNumberToChordAndRoot = function(arg: values.PlaybackNumberValue | values.PlaybackAnchorValue, songIterator: SongIterator) { let anchorChord, root; - if(typeof arg == 'number') { - anchorChord = MelodicBeatLiteral.getAnchorChord( + if(arg.type === 'number') { + anchorChord = getAnchorChord( null, songIterator, 1); - root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, arg, 4); - } else if(arg.anchor) { - anchorChord = MelodicBeatLiteral.getAnchorChord( - arg.anchor, songIterator, 1); - root = MelodicBeatLiteral.anchorChordToRoot(anchorChord, 1, 4); + root = anchorChordToRoot(anchorChord, arg.value, 4); + } else { + anchorChord = getAnchorChord( + arg.value, songIterator, 1); + root = anchorChordToRoot(anchorChord, 1, 4); } return [anchorChord, root]; }; @@ -273,19 +274,18 @@ define('progression', }, (args, songIterator, scope, argErr) => { for(let i in args) { - let arg = args[i]; - let [,goal] = anchorOrNumberToChordAndRoot(arg, songIterator); - if(!goal) { - argErr(`Arguments of "progression" must be numbers or anchors (got ${args}).`); + if(args[0].type !== 'number' && args[0].type !== 'anchor') { + argErr(`Arguments of "progression" must be numbers or anchors`); } - let actualMeasure = songIterator.getRelative(Number(i)); - if(!actualMeasure) return false; - let actualChord = MelodicBeatLiteral.normalizeChord(actualMeasure.beats[0].chord); - let actual = MelodicBeatLiteral.anchorChordToRoot( + const [,goal] = anchorOrNumberToChordAndRoot(args[0] as values.PlaybackNumberValue | values.PlaybackAnchorValue, songIterator); + const actualMeasure = songIterator.getRelative(Number(i)); + if(!actualMeasure) return new values.PlaybackBooleanValue(false); + const actualChord = normalizeChordForTonal(actualMeasure.beats[0].chord); + const actual = anchorChordToRoot( actualChord, 1, 4); - if(actual != goal) return false; + if(actual != goal) return new values.PlaybackBooleanValue(false); } - return true; + return new values.PlaybackBooleanValue(true); }); define('in-scale', { @@ -294,14 +294,15 @@ define('in-scale', returns: 'boolean' }, (args, songIterator, scope, argErr) => { - let [,note] = anchorOrNumberToChordAndRoot(args[0], songIterator); - let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1], songIterator); - if(!note || !goalChord) { - argErr(`Arguments of "in-scale" must be numbers or anchors (got ${args}).`); + if((args[0].type !== 'number' && args[0].type !== 'anchor') + || args[1].type !== 'number' && args[1].type !== 'anchor') { + argErr(`Arguments of "in-scale" must be numbers or anchors`); } - let goalScaleName = MelodicBeatLiteral.chordToScaleName(goalChord); + let [,note] = anchorOrNumberToChordAndRoot(args[0] as values.PlaybackNumberValue | values.PlaybackAnchorValue, songIterator); + let [goalChord, goalTonic] = anchorOrNumberToChordAndRoot(args[1] as values.PlaybackNumberValue | values.PlaybackAnchorValue, songIterator); + let goalScaleName = chordToScaleName(goalChord); let goalScale = tonal.Scale.notes(goalTonic, goalScaleName); - return goalScale.includes(note); + return new values.PlaybackBooleanValue(goalScale.includes(note)); }); define('beat-defined', { @@ -311,8 +312,9 @@ define('beat-defined', }, (args, songIterator, scope, argErr) => { let measure = songIterator.getRelative(0); - if(!measure) return false; - return measure.beats[args[0]].chord !== null; + if(!measure) return new values.PlaybackBooleanValue(false); + const index = (args[0] as values.PlaybackNumberValue).value; + return new values.PlaybackBooleanValue(measure.beats[index].chord !== null); }); /*** pattern-only functions ***/ @@ -322,14 +324,14 @@ define('chance', { types: ['number'], scope: 'pattern', - returns: Nil + returns: 'Nil' }, (args, songIterator, scope, argErr) => { - if(args[0] < 0 || args[0] > 1) { - argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive) (got ${args}).`); + if((args[0] as values.PlaybackNumberValue).value < 0 || (args[0] as values.PlaybackNumberValue).value > 1) { + argErr(`Argument 1 of "chance" must be in range 0-1 (inclusive)`); } scope.vars.set('chance', args[0]); - return Nil; + return new values.PlaybackNilValue(); }); export {definitions}; diff --git a/src/ast/music_utils.ts b/src/ast/music_utils.ts new file mode 100644 index 0000000..e92c8e4 --- /dev/null +++ b/src/ast/music_utils.ts @@ -0,0 +1,79 @@ +import SongIterator from 'notochord-song/types/songiterator'; +import tonal from '../lib/tonal.min.js'; + +export function normalizeChordForTonal(chord: string = ''): string { + return chord + .replace(/-/g, '_') // tonal uses _ over - for minor7 + .replace(/minor|min/g, 'm'); // tonal is surprisingly bad at identifying minor chords?? +} + +type Anchor = 'KEY' | 'NEXT' | 'STEP' | 'ARPEGGIATE'; +export function getAnchorChord(anchor: Anchor, songIterator: SongIterator, currentTime: number) { + let anchorChord: string; + switch(anchor) { + case 'KEY': { + anchorChord = songIterator.song.getTransposedKey(); + } + case 'NEXT': { + let nextMeasure = songIterator.getRelative(1); + if(nextMeasure) { + anchorChord = nextMeasure.beats[0].chord; + } else { + anchorChord = songIterator.song.getTransposedKey(); + } + } + case 'STEP': + case 'ARPEGGIATE': { + /* + let prev = songIterator.getRelative(0)[0]; //??? + if(!this.parentMeasure) console.log('tttttttt', this); + let next = this.parentMeasure.getNextStaticBeatRoot( + this.indexInMeasure, + songIterator + );*/ + + } + default: { + // crawl backward through this measure to get the last set beat + let lastSetBeat = Math.floor(currentTime); + let iteratorMeasure = songIterator.getRelative(0); + if(!iteratorMeasure) break; + do { + const beat = iteratorMeasure.beats[lastSetBeat] + anchorChord = beat && beat.chord; + lastSetBeat--; + } while(!anchorChord); + } + } + return normalizeChordForTonal(anchorChord); +} + +export function anchorChordToRoot(anchorChord: string, degree: number, octave: number): string { + let anchorTonic = tonal.Chord.tokenize(anchorChord)[0]; + let anchorScaleName = chordToScaleName(anchorChord); + let scalePCs = tonal.Scale.notes(anchorTonic, anchorScaleName); + let rootPC = scalePCs[degree - 1]; + return tonal.Note.from({oct: octave}, rootPC); +} + +export function chordToScaleName(chord: string) { + let chordType = tonal.Chord.tokenize(chord)[1]; + + // @TODO: make this more robust + let names = tonal.Chord.props(chordType).names; + if(names.includes('dim')) return 'diminished'; + if(names.includes('aug')) return 'augmented'; + if(names.includes('Major')) return 'major'; + if(names.includes('minor')) return 'minor'; + if(names.includes('minor7')) return 'dorian'; + if(names.includes('Dominant')) return 'mixolydian'; + // if none of the above match, do our best to find the closest fit + let closestScale = 'major' + names.forEach(name => { + if(name.startsWith('dim')) closestScale = 'diminished'; + if(name.startsWith('aug')) closestScale = 'augmented'; + if(name.startsWith('M')) closestScale = 'major'; + if(name.startsWith('m')) closestScale = 'minor'; + }); + return closestScale; +} \ No newline at end of file diff --git a/src/ast/type_utils.ts b/src/ast/type_utils.ts deleted file mode 100644 index 9ea6800..0000000 --- a/src/ast/type_utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -const Nil: unique symbol = Symbol('Nil'); -type Nil = typeof Nil; -let cast_bool = function(arg) { - if(arg === Nil || arg === false) { - return false; - } else { - return true; - } -} - -export {Nil, cast_bool}; diff --git a/src/parser/grammar.js b/src/parser/grammar.js index fd0b1d1..2516554 100644 --- a/src/parser/grammar.js +++ b/src/parser/grammar.js @@ -2,8 +2,9 @@ // http://github.com/Hardmath123/nearley function id(x) { return x[0]; } -import lexer from '../lexer/lexer.js' ; -import * as ast from '../ast/ast_nodes.js'; +import lexer from '../lexer/lexer' ; +import * as ast from '../ast/ast_nodes'; +import * as values from '../values/values'; let Lexer = lexer; let ParserRules = [ {"name": "main$macrocall$2", "symbols": ["TopLevelStatement"]}, @@ -69,11 +70,11 @@ let ParserRules = [ {"name": "FunctionCallExpression$macrocall$1", "symbols": ["FunctionCallExpression$macrocall$2", "FunctionCallExpression$macrocall$1$ebnf$1"], "postprocess": d => d[0].concat(d[1])}, {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, "_?", "FunctionCallExpression$macrocall$1", "_?", {"literal":")"}], "postprocess": d => new ast.FunctionCall(d[0], d[4])}, {"name": "FunctionCallExpression", "symbols": ["Identifier", "_?", {"literal":"("}, {"literal":")"}], "postprocess": d => new ast.FunctionCall(d[0], [])}, - {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": id}, + {"name": "FunctionCallArgument", "symbols": ["NumericExpression"], "postprocess": d => new values.PlaybackNumberValue(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["StringLiteral"], "postprocess": d => new values.PlaybackStringValue(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["BooleanLiteral"], "postprocess": d => new values.PlaybackBooleanValue(d[0])}, {"name": "FunctionCallArgument", "symbols": ["PatternExpression"], "postprocess": id}, - {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new ast.AnchorArgument(d[0])}, + {"name": "FunctionCallArgument", "symbols": ["BL_PP_Anchor"], "postprocess": d => new values.PlaybackAnchorValue(d[0])}, {"name": "FunctionCallArgument", "symbols": [{"literal":"not"}, "_", "FunctionCallArgument"], "postprocess": d => new ast.BooleanNot(d[2])}, {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"and"}, "_", "FunctionCallArgument"], "postprocess": d => new ast.BooleanAnd(d[0], d[4])}, {"name": "FunctionCallArgument", "symbols": ["FunctionCallArgument", "_", {"literal":"or"}, "_", "FunctionCallArgument"], "postprocess": d => new ast.BooleanOr(d[0], d[4])}, diff --git a/src/parser/grammar.ne b/src/parser/grammar.ne index 9c8a223..6a50e3a 100644 --- a/src/parser/grammar.ne +++ b/src/parser/grammar.ne @@ -1,8 +1,9 @@ # import the lexer @preprocessor esmodule @{% -import lexer from '../lexer/lexer' ; -import * as ast from '../ast/ast_nodes'; + import lexer from '../lexer/lexer' ; + import * as ast from '../ast/ast_nodes'; + import * as values from '../values/values'; %} @lexer lexer @@ -52,11 +53,11 @@ JoinedPatternExpression -> SEP_LIST_MIN2[PatternExpression_NoJoin, "&"] {% d => # functions FunctionCallExpression -> Identifier _? "(" _? SPACED_LIST[FunctionCallArgument] _? ")" {% d => new ast.FunctionCall(d[0], d[4]) %} | Identifier _? "(" ")" {% d => new ast.FunctionCall(d[0], []) %} -FunctionCallArgument -> NumericExpression {% id %} - | StringLiteral {% id %} - | BooleanLiteral {% id %} +FunctionCallArgument -> NumericExpression {% d => new values.PlaybackNumberValue(d[0]) %} + | StringLiteral {% d => new values.PlaybackStringValue(d[0]) %} + | BooleanLiteral {% d => new values.PlaybackBooleanValue(d[0]) %} | PatternExpression {% id %} - | BL_PP_Anchor {% d => new ast.AnchorArgument(d[0]) %} + | BL_PP_Anchor {% d => new values.PlaybackAnchorValue(d[0]) %} | "not" _ FunctionCallArgument {% d => new ast.BooleanNot(d[2]) %} | FunctionCallArgument _ "and" _ FunctionCallArgument {% d => new ast.BooleanAnd(d[0], d[4]) %} | FunctionCallArgument _ "or" _ FunctionCallArgument {% d => new ast.BooleanOr(d[0], d[4]) %} diff --git a/src/values/beatValues.ts b/src/values/beatValues.ts new file mode 100644 index 0000000..d50053e --- /dev/null +++ b/src/values/beatValues.ts @@ -0,0 +1,76 @@ +import { PlaybackValueBase } from './values'; + +type Anchor = 'KEY' | 'NEXT' | 'STEP' | 'ARPEGGIATE'; +const anchorReverseMap = {'KEY': 'k', 'NEXT': 'n', 'STEP': 's', 'ARPEGGIATE': 'a'}; + +export class PlaybackAnchorValue implements PlaybackValueBase { + public type: 'anchor' = 'anchor'; + public value: Anchor; + constructor(value: Anchor) { this.value = value; } + public toBoolean() { return true; } + public toOutputString() { return anchorReverseMap[this.value]; } +} + +abstract class PlaybackBeatValue implements PlaybackValueBase { + public type = null; + public value: any; + public toBoolean() { return true; } + public abstract toOutputString(): string; +} +type TimePart = { + time: 'auto' | number; + flag?: 'STACCATO' | 'ACCENTED' +}; +type PitchPart = { + degree: number; + anchor?: Anchor; + roll?: 'ROLL_UP' | 'ROLL_DOWN'; + chord: boolean; +}; + +type OctavePart = number | 'inherit'; + +export class PlaybackMelodicBeatValue extends PlaybackBeatValue { + public type: 'melodic_beat' = 'melodic_beat'; + public value = { + time: null as TimePart, + pitch: null as PitchPart, + octave: null as OctavePart, + } + constructor(time: TimePart = {time: 'auto'}, pitch: PitchPart, octave: OctavePart = 'inherit') { + super(); + this.value.time = time; + this.value.pitch = pitch; + this.value.octave = octave; + } + public toOutputString() { + const timeFlag = this.time.flag ? (this.time.flag === 'ACCENTED' ? 'a' : 's') : ''; + const timePart = `${this.time.time === 'auto' ? '' : this.time.time}${timeFlag}`; + const pitchAnchor = this.pitch.anchor ? anchorReverseMap[this.pitch.anchor]: ''; + const pitchRoll = this.pitch.roll ? (this.pitch.roll === 'ROLL_UP' ? 'r' : 'rd') : ''; + const pitchPart = `:${pitchAnchor}${this.pitch.degree || ''}${this.pitch.chord ? 'c' : ''}${pitchRoll}`; + const octavePart = this.octave === 'inherit' ? '' : `:${this.octave}`; + return `${timePart}${pitchPart}${octavePart}`; + } + get time() { return this.value.time; } + get pitch() { return this.value.pitch; } + get octave() { return this.value.octave; } +} + +export class PlaybackDrumBeatValue extends PlaybackBeatValue { + public type: 'drum_beat' = 'drum_beat'; + public value = { + time: null as number, + accented: null as boolean, + } + constructor(time: number, accented: boolean = false) { + super(); + this.value.time = time; + this.value.accented = accented; + } + public toOutputString() { + return `${this.time}${this.accented ? 'a' : ''}`; + } + get time() { return this.value.time; } + get accented() { return this.value.accented; } +} \ No newline at end of file diff --git a/src/values/values.ts b/src/values/values.ts new file mode 100644 index 0000000..a5fd52d --- /dev/null +++ b/src/values/values.ts @@ -0,0 +1,64 @@ +import { PlaybackMelodicBeatValue, PlaybackDrumBeatValue, PlaybackAnchorValue } from './beatValues'; + +export abstract class PlaybackValueBase { + public type: string; + public value: any; + public abstract toBoolean(): boolean; + public abstract toOutputString(): string; +} + +export class PlaybackNilValue implements PlaybackValueBase { + public type: 'Nil' = 'Nil'; + public value: null = null; + public toBoolean() { return false; } + public toOutputString() { return 'Nil'; } +} + +export class PlaybackStringValue implements PlaybackValueBase { + public type: 'string' = 'string'; + public value: string; + constructor(value: string) { this.value = value; } + public toBoolean() { return this.value !== ''; } + public toOutputString() { + // @TODO: store raw value from tokenizer? (which may not always exist for programmatically-generated strings) + // At least this is consistent... + return `"${this.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`; + } +} + +export class PlaybackNumberValue implements PlaybackValueBase { + public type: 'number' = 'number'; + public value: number; + constructor(value: number) { this.value = value; } + public toInteger() { return Math.floor(this.value); } + public toBoolean() { return this.value !== 0; } + public toOutputString() { return this.value.toString(); } +} + +export class PlaybackBooleanValue implements PlaybackValueBase { + public type: 'boolean' = 'boolean'; + public value: boolean; + constructor(value: boolean) { this.value = value; } + public toBoolean() { return this.value; } + public toOutputString() { return this.value ? 'true' : 'false'; } +} + +export class PlaybackTimeSignatureValue implements PlaybackValueBase { + public type: 'time_signature' = 'time_signature'; + public value: [number, number]; + constructor(value: [number, number]) { this.value = value; } + public toBoolean() { return true; } + public toOutputString() { return `${this.value[0]} / ${this.value[1]}`; } +} + +export { PlaybackMelodicBeatValue, PlaybackDrumBeatValue, PlaybackAnchorValue }; + +export type PlaybackValue = + | PlaybackNilValue + | PlaybackStringValue + | PlaybackNumberValue + | PlaybackBooleanValue + | PlaybackMelodicBeatValue + | PlaybackDrumBeatValue + | PlaybackAnchorValue + | PlaybackTimeSignatureValue; From a33b7a0f15dcb1d0c85dfb59cef1aa960326cc28 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Tue, 28 Apr 2020 19:27:16 -0600 Subject: [PATCH 4/6] docs --- README.md | 57 ++++++++++++++++++++++++++++++++++++------- docs/styles/README.md | 50 ++++++++++++++++++++++++------------- 2 files changed, 81 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 6309cae..004685b 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,46 @@ library that can play a given set of chords in that style. It's a big part of [Notochord](https://notochord.github.io/notochord/demo/), a lead-sheet editor that is currently under construction. -## User Guide (this should move) +It's written in TypeScript with a parser written in +[nearley](https://github.com/kach/nearley). -I recommend the file extension `.play` for styles, because how awesome is that? +## Documentation (this should move) -More to come. +### API + +Playback is built to work with [notochord-song](https://github.com/notochord/notochord-song) +songs. The package exports two constructors: + +- `Player`, which handles playing the song. + - `new Player()` or `new Player(AudioContext)` + - `player.setStyle(PlaybackStyle): Promise` + - `player.play(mySong)` - takes a notochord-song. Don't call this until + `setStyle` has finished +- `PlaybackStyle`, which represents a style + - `new PlaybackStyle(pathToStyle)` - takes a string relative filepath or URL + (see the [resolution algorithm](https://github.com/notochord/playback/blob/master/src/loader/loader.js)) + +```javascript +import Song from 'notochord-song'; +import { Player, PlaybackStyle } from 'playback'; + +const mySong = new Song(/* serialized song, see notochord-song docs */); + +const player = new Player(); +const style = new PlaybackStyle('./styles/swing.play'); + +player.setStyle(style) + .then(() => { + // note that browsers may prevent playing audio if the user hasn't initiated it + player.play(mySong); + }); +``` + +### How to write a style + +For the documentation on how to write a style, see +[https://github.com/notochord/playback/tree/master/docs/styles](). I recommend +the file extension `.play` for styles, because how awesome is that? ## Inspiration @@ -30,11 +65,12 @@ So I set off to create my very own language to define a playback style. The end. ## Navigating this repository -- `dist/playback.js` - the finished product +- `dist/` - the finished product, compiled to diferent kinds of JS as needed - `src/` - the unbundled source code - - `index.js` - this doesn't do much except tie all the other bits together. - - `loader/` - the loader loads files from the filesystem all promise-like. - I'll probably remove the whole directory but forget to update the readme. + - `playback.ts` - this doesn't do much except tie all the other bits together. + - `loader/` - the loader loads files from the filesystem and/or via http + request, per a resolution algorithm laid out in a comment at the top of that + file. It's real hacky and probably needs to change significantly. - `lexer/` - the lexer takes a .play file as a string and figures out where one token ends and another begins. See [Wikipedia](https://en.wikipedia.org/wiki/Lexical_analysis) for a better @@ -46,10 +82,13 @@ So I set off to create my very own language to define a playback style. The end. there might be a compilation step here but it doesn't so there's not.) - `grammar.ne` - the definition of the language's grammar. It's written in Nearley's BNF-like syntax. - - `parser.js` - ties everything nicely together in a promise-y API so you + - `grammar.js` - ignore this, it's compiled from the `.ne` file. + - `parser.ts` - ties everything nicely together in a promise-y API so you don't have to talk to nearley at all. - `ast/` - the definitions for the nodes of the AST. This is where you'll find the code for what a style is actually doing when you're playing it. + - `values/` - a bunch of classes that represent different kinds of values in + Playback, like strings, numbers, etc. - `styles/` - some styles. I might move these to their own repo later - `test/` - Most directories in `src/` have their tests defined locally, but they're bundled together here. (run with `npm test` or `npm test -- -v` for @@ -59,7 +98,7 @@ So I set off to create my very own language to define a playback style. The end. - `npm test` - run the test suite - `npm run build` - compile and bundle -- `npm run playgrouns` - open the playground +- `npm run playground` - open the playground ## Credits diff --git a/docs/styles/README.md b/docs/styles/README.md index 92a752f..800b438 100644 --- a/docs/styles/README.md +++ b/docs/styles/README.md @@ -321,10 +321,10 @@ makes it possible to do tuplets: After the number, there are 2 flags allowed: -| Flag | Meaning | -| ---- | ------- | -| `s` | Staccato (by default, notes are sustained until the next note) | -| `a` | Accented (volume boost) | +| Flag | Example | Meaning | +| ---- | ------- | ------- | +| `s` | `1s:1` | Staccato (by default, notes are sustained until the next note) | +| `a` | `1a:1` | Accented (volume boost) | (TODO: it feels valid for a note to be both accented and staccato) @@ -332,25 +332,29 @@ If the number is omitted, a singleton flag is allowed. #### Note/chord part -##### Single-note - -The note part by default describes a note relative to the chord on the current -beat. This can be changed by using an "anchor": +The note part allows you to express a note or chord relative to what's going on +in the song. There are several options for whhat you want to "anchor" a note +relatively to: | Anchor | Notes relative to | | ------ | ----------------- | -| (none) | Chord in current beat of measure | -| `k` | Key of the song | -| `n` | Chord in first beat of the next measure | +| (none) | The current chord in the song | +| `k` | The key of the song | +| `n` | The chord in first beat of the next measure | +| `a` | Arpeggiate automatically between the previous and next beats | +| `s` | Move stepwise between the previous and next beats | -A number is required if there's no anchor. If there's an anchor and the number -is omitted, it's implied to be the 1 of that chord. If there is a number, the -note is that many scale degrees above the root of the anchoring chord (in the -chord's scale, not the scale of the song's key.) For example: +##### Single-note + +For single-note note parts, a number is required if there's no anchor. If +there's an anchor and the number is omitted, it's implied to be the 1 of that +chord. If there is a number, the note is that many scale degrees above the root +of the anchoring chord (in the chord's scale, not the scale of the song's key.) +For example: ``` -< :1 > // Root of the current chord -< :5 > // 5th of the current chord +< :1 > // Root of the current chord of the song +< :5 > // 5th of the current chord of the song < :k > // Root of the key of the song < :k1 > // Root of the key of the song < :k5 > // 5th in the scale of the song's key @@ -358,6 +362,8 @@ chord's scale, not the scale of the song's key.) For example: < :n5 > // 5th of the first chord in the next measure ``` +(TODO: add examples with `s` and `a`) + (TODO: `s` and `a` are not anchors and must not be combined with a number nor with `c` -- or are passing chords fine? idc) @@ -376,6 +382,16 @@ The `c` flag may be followed by one of the following: | `r` | Roll the chord upwards | | `rd` | Roll the chord downwards | +``` +< :c > // Play the current chord of the song +< :5c > // Play the chord that is a 5th above the current chord of the song +< :kc > // Play the chord of the root of the key of the song +< :k1c > // Play the chord of the root of the key of the song +< :k5 > // Play the chord that is a 5th above the root of the song's key +< :nc > // Play the chord of the root of the first chord in the next measure +< :n5c > // Play the chord that is a 5th above the first chord in the next measure +``` + #### Octave part The octave part allows the user to specify the octave of the note or chord. It From 5e1a713aa75157fdfde5878f319b02a33b9945b2 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Tue, 28 Apr 2020 19:31:10 -0600 Subject: [PATCH 5/6] There are links to the playground file so unrename it back to index.html --- docs/styles/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/styles/README.md b/docs/styles/README.md index 800b438..934466d 100644 --- a/docs/styles/README.md +++ b/docs/styles/README.md @@ -4,8 +4,6 @@ A style is a text file that describes how to play a song in a musical style. We recommend the file extension `.play`, but you can use any file extension you like (see the API documentation) (TODO link) -[Demo?](https://notochord.github.io/playback/test/); - ## Overview A .play file will look something like this: From 0e4d862485f83995c71483fd50a73f1bbba62614 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Tue, 28 Apr 2020 19:31:57 -0600 Subject: [PATCH 6/6] Whoops, missed adding the most important file in the prev commit --- test/{playground.html => index.html} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{playground.html => index.html} (100%) diff --git a/test/playground.html b/test/index.html similarity index 100% rename from test/playground.html rename to test/index.html