12tet
Version:
Music theory library for generating and working with chords, modes, intervals, etc.
273 lines (272 loc) • 8.98 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.interval = exports.getIntervalBetweenNotes = exports.getIntervalBetweenIntervals = exports.intervalByShortIntervalName = exports.isIntervalIdentifier = exports.isInterval = exports.isIntervalDistance = exports.isComplexIntervalDistance = exports.standardIntervalDistances = exports.isStandardIntervalDistance = exports.shortIntervalNames = exports.isShortIntervalName = exports.alternateIntervalNames = exports.isAlternateIntervalName = exports.intervalNames = exports.isIntervalName = void 0;
const utils_1 = require("../utils");
const note_1 = require("../note");
// Standard inter-octave interval names
const INTERVAL_NAMES = [
'Perfect Unison',
'Minor Second',
'Major Second',
'Minor Third',
'Major Third',
'Perfect Fourth',
'Tritone',
'Perfect Fifth',
'Minor Sixth',
'Major Sixth',
'Minor Seventh',
'Major Seventh',
'Perfect Octave',
];
function isIntervalName(interval) {
return INTERVAL_NAMES.includes(interval);
}
exports.isIntervalName = isIntervalName;
exports.intervalNames = [...INTERVAL_NAMES];
// Alternate and extra-octave interval names
const ALTERNATE_INTERVAL_NAMES = [
'Semitone',
'Tone',
'Trisemitone',
'Tritone',
'Tritave',
'Double Octave',
'Diminished Second',
'Augmented Unison',
'Diminished Third',
'Augmented Second',
'Diminished Fourth',
'Augmented Third',
'Diminished Fifth',
'Augmented Fourth',
'Diminished Sixth',
'Augmented Fifth',
'Diminished Seventh',
'Augmented Sixth',
'Diminished Octave',
'Augmented Seventh',
'Minor Ninth',
'Major Ninth',
'Minor Tenth',
'Major Tenth',
'Perfect Eleventh',
'Perfect Twelfth',
'Minor Thirteenth',
'Major Thirteenth',
'Minor Fourteenth',
'Major Fourteenth',
'Perfect Fifteenth',
'Diminished Ninth',
'Augmented Octave',
'Diminished Tenth',
'Augmented Ninth',
'Diminished Eleventh',
'Augmented Tenth',
'Diminished Twelfth',
'Augmented Eleventh',
'Diminished Thirteenth',
'Augmented Twelfth',
'Diminished Fourteenth',
'Augmented Thirteenth',
'Diminished Fifteenth',
'Augmented Fourteenth',
'Augmented Fifteenth',
'Half Tone',
'Half Step',
'Whole Step'
];
function isAlternateIntervalName(interval) {
return ALTERNATE_INTERVAL_NAMES.includes(interval);
}
exports.isAlternateIntervalName = isAlternateIntervalName;
exports.alternateIntervalNames = [...ALTERNATE_INTERVAL_NAMES];
// Abbreviated inter-octave interval names
const SHORT_INTERVAL_NAMES = ['P1', 'm2', 'M2', 'm3', 'M3', 'P4', 'TT', 'P5', 'm6', 'M6', 'm7', 'M7', 'P8'];
function isShortIntervalName(interval) {
return SHORT_INTERVAL_NAMES.includes(interval);
}
exports.isShortIntervalName = isShortIntervalName;
exports.shortIntervalNames = [...SHORT_INTERVAL_NAMES];
// A number representing the semitone distance between two intervals inside an octaves length
const STANDARD_INTERVAL_DISTANCES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
function isStandardIntervalDistance(intervalDistance) {
return intervalDistance <= 12;
}
exports.isStandardIntervalDistance = isStandardIntervalDistance;
exports.standardIntervalDistances = [...STANDARD_INTERVAL_DISTANCES];
function isComplexIntervalDistance(intervalDistance) {
return intervalDistance > 12;
}
exports.isComplexIntervalDistance = isComplexIntervalDistance;
function isIntervalDistance(intervalDistance) {
return Number.isInteger(intervalDistance);
}
exports.isIntervalDistance = isIntervalDistance;
function isInterval(interval) {
return interval.name !== undefined &&
interval.shortName !== undefined;
}
exports.isInterval = isInterval;
function isIntervalIdentifier(intervalIdentifier) {
if (isIntervalName(intervalIdentifier) ||
isShortIntervalName(intervalIdentifier) ||
isIntervalDistance(intervalIdentifier) ||
isComplexIntervalDistance(intervalIdentifier) ||
isInterval(intervalIdentifier)) {
return true;
}
else {
return false;
}
}
exports.isIntervalIdentifier = isIntervalIdentifier;
// Metadata of the inter-octave intervals
exports.intervalByShortIntervalName = {
P1: {
length: 0,
name: 'Perfect Unison',
shortName: 'P1',
alternateNames: ['Diminished Second'],
tension: 0
},
m2: {
length: 1,
name: 'Minor Second',
shortName: 'm2',
alternateNames: ['Augmented Unison', 'Semitone', 'Half Tone', 'Half Step'],
tension: 4
},
M2: {
length: 2,
name: 'Major Second',
shortName: 'M2',
alternateNames: ['Diminished Third', 'Tone', 'Whole Step'],
tension: 3
},
m3: {
length: 3,
name: 'Minor Third',
shortName: 'm3',
alternateNames: ['Augmented Second'],
tension: 2
},
M3: {
length: 4,
name: 'Major Third',
shortName: 'M3',
alternateNames: ['Diminished Fourth'],
tension: 1
},
P4: {
length: 5,
name: 'Perfect Fourth',
shortName: 'P4',
alternateNames: ['Augmented Third'],
tension: 1
},
TT: {
length: 6,
name: 'Tritone',
shortName: 'TT',
alternateNames: ['Augmented Fourth', 'Diminished Fifth'],
tension: 5
},
P5: {
length: 7,
name: 'Perfect Fifth',
shortName: 'P5',
alternateNames: ['Diminished Sixth'],
tension: 0
},
m6: {
length: 8,
name: 'Minor Sixth',
shortName: 'm6',
alternateNames: ['Augmented Fifth'],
tension: 2
},
M6: {
length: 9,
name: 'Major Sixth',
shortName: 'M6',
alternateNames: ['Diminished Seventh'],
tension: 1
},
m7: {
length: 10,
name: 'Minor Seventh',
shortName: 'm7',
alternateNames: ['Augmented Sixth'],
tension: 3
},
M7: {
length: 11,
name: 'Major Seventh',
shortName: 'M7',
alternateNames: ['Diminished Octave'],
tension: 4
},
P8: {
length: 12,
name: 'Perfect Octave',
shortName: 'P8',
alternateNames: ['Augmented Seventh'],
tension: 0
}
};
function getIntervalBetweenIntervals(first, second) {
const firstInterval = interval(first);
const secondInterval = interval(second);
const distance = secondInterval.length >= firstInterval.length ? secondInterval.length - firstInterval.length : (12 - firstInterval.length) + secondInterval.length;
return distance === 0 ? 12 : distance; // Prefer Perfect Octaves over Perfect Unisons
}
exports.getIntervalBetweenIntervals = getIntervalBetweenIntervals;
function getIntervalBetweenNotes(first, second) {
const firstTone = note_1.tonesByNote[first];
const secondTone = note_1.tonesByNote[second];
const distance = secondTone.index >= firstTone.index ? secondTone.index - firstTone.index : (11 - firstTone.index) + secondTone.index;
return interval(distance === 0 ? 12 : distance); // Prefer Perfect Octaves over Perfect Unisons
}
exports.getIntervalBetweenNotes = getIntervalBetweenNotes;
function interval(intervalIdentifier) {
if (isInterval(intervalIdentifier)) {
return intervalIdentifier;
}
else if (isIntervalName(intervalIdentifier)) {
const intervalData = Object.values(exports.intervalByShortIntervalName).find(element => element.name === intervalIdentifier);
if (!intervalData) {
throw TypeError(`Could not find interval with name ${intervalIdentifier}`);
}
else {
return intervalData;
}
}
else if (isShortIntervalName(intervalIdentifier)) {
return exports.intervalByShortIntervalName[intervalIdentifier];
}
else if (isStandardIntervalDistance(intervalIdentifier)) {
const intervalData = Object.values(exports.intervalByShortIntervalName).find(element => element.length === intervalIdentifier);
if (!intervalData) {
throw TypeError(`Could find find interval with distance ${intervalIdentifier}`);
}
else {
return intervalData;
}
}
else {
// With complex intervals, we want to normalize to Perfect Octaves, not Perfect Unisons
let normalizedValue = (0, utils_1.wrapValue)(intervalIdentifier, 12);
if (normalizedValue === 0) {
normalizedValue = 12;
}
const intervalData = Object.values(exports.intervalByShortIntervalName).find(element => element.length === normalizedValue);
if (!intervalData) {
throw TypeError(`Could not find interval with distance ${intervalIdentifier}`);
}
else {
return intervalData;
}
}
}
exports.interval = interval;