UNPKG

moment-of-symmetry

Version:

Moment of Symmetry (MOS) musical scale generation and analysis for Javascript

124 lines 4.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createMosScale = exports.createMosPattern = exports.generateScale = exports.generatePattern = exports.getDown = exports.calculatePeriodSize = exports.calculatePeriods = void 0; const xen_dev_utils_1 = require("xen-dev-utils"); const bjorklund_1 = require("./bjorklund"); const types_1 = require("../types"); /** * Calculate the number of periods in a MOS pattern */ function calculatePeriods(largeSteps, smallSteps) { return (0, xen_dev_utils_1.gcd)(largeSteps, smallSteps); } exports.calculatePeriods = calculatePeriods; /** * Calculate the period size of a MOS pattern */ function calculatePeriodSize(largeSteps, smallSteps) { const periods = calculatePeriods(largeSteps, smallSteps); return (largeSteps + smallSteps) / periods; } exports.calculatePeriodSize = calculatePeriodSize; /** * Get the number of bright generators to go down based on options */ function getDown(options, period, numPeriods) { let down = 0; if (options.up !== undefined) { down = period * numPeriods - numPeriods - options.up; if (options.down !== undefined && down !== options.down) { throw new types_1.InvalidParametersError('Incompatible up and down with the scale size'); } } else if (options.down !== undefined) { down = options.down; } if (down < 0) { throw new types_1.InvalidParametersError('Down must not be negative'); } if (down >= period * numPeriods) { throw new types_1.InvalidParametersError('Up must not be negative'); } if (down % numPeriods !== 0) { throw new types_1.InvalidParametersError('Up/down must be divisible by the number of periods'); } return down; } exports.getDown = getDown; /** * Generate a MOS pattern string */ function generatePattern(largeSteps, smallSteps, options) { if (!largeSteps) { return 's'.repeat(smallSteps); } if (!smallSteps) { return 'L'.repeat(largeSteps); } const brightest = (0, bjorklund_1.bjorklundStr)(largeSteps, smallSteps); const modes = []; let mode = brightest; while (true) { modes.push(mode); mode = mode.slice(1) + mode[0]; if (mode === brightest) { break; } } // Lexicographic order corresponds to brightness modes.sort(); const numPeriods = calculatePeriods(largeSteps, smallSteps); const period = calculatePeriodSize(largeSteps, smallSteps); const brightGeneratorsDown = getDown(options !== null && options !== void 0 ? options : {}, period, numPeriods); return modes[brightGeneratorsDown / numPeriods]; } exports.generatePattern = generatePattern; /** * Generate a MOS scale from a pattern */ function generateScale(pattern, sizeOfLargeStep, sizeOfSmallStep) { let step = 0; const result = []; for (const character of pattern) { if (character === 'L') { step += sizeOfLargeStep; } else { step += sizeOfSmallStep; } result.push(step); } return result; } exports.generateScale = generateScale; /** * Create a complete MOS pattern object */ function createMosPattern(largeSteps, smallSteps, options) { const periods = calculatePeriods(largeSteps, smallSteps); const pattern = generatePattern(largeSteps, smallSteps, options); return { largeSteps, smallSteps, pattern, periods, }; } exports.createMosPattern = createMosPattern; /** * Create a complete MOS scale object */ function createMosScale(largeSteps, smallSteps, options) { var _a, _b; const mosPattern = createMosPattern(largeSteps, smallSteps, options); const sizeOfLargeStep = (_a = options === null || options === void 0 ? void 0 : options.sizeOfLargeStep) !== null && _a !== void 0 ? _a : 2; const sizeOfSmallStep = (_b = options === null || options === void 0 ? void 0 : options.sizeOfSmallStep) !== null && _b !== void 0 ? _b : 1; return { ...mosPattern, degrees: generateScale(mosPattern.pattern, sizeOfLargeStep, sizeOfSmallStep), sizeOfLargeStep, sizeOfSmallStep, }; } exports.createMosScale = createMosScale; //# sourceMappingURL=pattern.js.map