mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-16 16:48:00 +00:00
1451 lines
37 KiB
JavaScript
1451 lines
37 KiB
JavaScript
!function(e){
|
|
if("object"===typeof exports&&"undefined"!==typeof module){
|
|
module.exports=e();
|
|
}else if("function"===typeof define&&define.amd){
|
|
define([],e);
|
|
}else{
|
|
var f;"undefined"!==typeof window?f=window:"undefined"!==typeof global?f=global:"undefined"!==typeof self&&(f=self),f.teoria=e();
|
|
}
|
|
}(function(){
|
|
var define,module,exports;return (function e(t,n,r){
|
|
function s(o,u){
|
|
if(!n[o]){
|
|
if(!t[o]){
|
|
var a=typeof require==="function"&&require;if(!u&&a){
|
|
return a(o,!0);
|
|
}if(i){
|
|
return i(o,!0);
|
|
}var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f;
|
|
}var l=n[o]={ exports : {} };t[o][0].call(l.exports,function(e){
|
|
var n=t[o][1][e];return s(n?n:e);
|
|
},l,l.exports,e,t,n,r);
|
|
}return n[o].exports;
|
|
}var i=typeof require==="function"&&require;for(var o=0;o<r.length;o++){
|
|
s(r[o]);
|
|
}return s;
|
|
})({ 1 : [function(require,module,exports){
|
|
var Note = require("./lib/note");
|
|
var Interval = require("./lib/interval");
|
|
var Chord = require("./lib/chord");
|
|
var Scale = require("./lib/scale");
|
|
|
|
// never thought I would write this, but: Legacy support
|
|
function intervalConstructor(from, to) {
|
|
// Construct a Interval object from string representation
|
|
if (typeof from === "string") {
|
|
return Interval.toCoord(from);
|
|
}
|
|
|
|
if (typeof to === "string" && from instanceof Note) {
|
|
return Interval.from(from, Interval.toCoord(to));
|
|
}
|
|
|
|
if (to instanceof Interval && from instanceof Note) {
|
|
return Interval.from(from, to);
|
|
}
|
|
|
|
if (to instanceof Note && from instanceof Note) {
|
|
return Interval.between(from, to);
|
|
}
|
|
|
|
throw new Error("Invalid parameters");
|
|
}
|
|
|
|
intervalConstructor.toCoord = Interval.toCoord;
|
|
intervalConstructor.from = Interval.from;
|
|
intervalConstructor.between = Interval.between;
|
|
intervalConstructor.invert = Interval.invert;
|
|
|
|
function noteConstructor(name, duration) {
|
|
if (typeof name === "string") {
|
|
return Note.fromString(name, duration);
|
|
} else {
|
|
return new Note(name, duration);
|
|
}
|
|
}
|
|
|
|
noteConstructor.fromString = Note.fromString;
|
|
noteConstructor.fromKey = Note.fromKey;
|
|
noteConstructor.fromFrequency = Note.fromFrequency;
|
|
noteConstructor.fromMIDI = Note.fromMIDI;
|
|
|
|
function chordConstructor(name, symbol) {
|
|
if (typeof name === "string") {
|
|
var root, octave;
|
|
root = name.match(/^([a-h])(x|#|bb|b?)/i);
|
|
if (root && root[0]) {
|
|
octave = typeof symbol === "number" ? symbol.toString(10) : "4";
|
|
return new Chord(Note.fromString(root[0].toLowerCase() + octave),
|
|
name.substr(root[0].length));
|
|
}
|
|
} else if (name instanceof Note) {
|
|
return new Chord(name, symbol);
|
|
}
|
|
|
|
throw new Error("Invalid Chord. Couldn't find note name");
|
|
}
|
|
|
|
function scaleConstructor(tonic, scale) {
|
|
tonic = (tonic instanceof Note) ? tonic : teoria.note(tonic);
|
|
return new Scale(tonic, scale);
|
|
}
|
|
|
|
var teoria = {
|
|
note : noteConstructor,
|
|
|
|
chord : chordConstructor,
|
|
|
|
interval : intervalConstructor,
|
|
|
|
scale : scaleConstructor,
|
|
|
|
Note : Note,
|
|
Chord : Chord,
|
|
Scale : Scale,
|
|
Interval : Interval
|
|
};
|
|
|
|
require("./lib/sugar")(teoria);
|
|
exports = module.exports = teoria;
|
|
|
|
},{ "./lib/chord" : 2,"./lib/interval" : 3,"./lib/note" : 5,"./lib/scale" : 6,"./lib/sugar" : 7 }],2 : [function(require,module,exports){
|
|
var daccord = require("daccord");
|
|
var knowledge = require("./knowledge");
|
|
var Note = require("./note");
|
|
var Interval = require("./interval");
|
|
|
|
function Chord(root, name) {
|
|
if (!(this instanceof Chord)) {
|
|
return new Chord(root, name);
|
|
}
|
|
name = name || "";
|
|
this.name = root.name().toUpperCase() + root.accidental() + name;
|
|
this.symbol = name;
|
|
this.root = root;
|
|
this.intervals = [];
|
|
this._voicing = [];
|
|
|
|
var bass = name.split("/");
|
|
if (bass.length === 2 && bass[1].trim() !== "9") {
|
|
name = bass[0];
|
|
bass = bass[1].trim();
|
|
} else {
|
|
bass = null;
|
|
}
|
|
|
|
this.intervals = daccord(name).map(Interval.toCoord);
|
|
this._voicing = this.intervals.slice();
|
|
|
|
if (bass) {
|
|
var intervals = this.intervals, bassInterval, note;
|
|
// Make sure the bass is atop of the root note
|
|
note = Note.fromString(bass + (root.octave() + 1)); // crude
|
|
|
|
bassInterval = Interval.between(root, note);
|
|
bass = bassInterval.simple();
|
|
bassInterval = bassInterval.invert().direction("down");
|
|
|
|
this._voicing = [bassInterval];
|
|
for (var i = 0, length = intervals.length; i < length; i++) {
|
|
if (!intervals[i].simple().equal(bass)) {
|
|
this._voicing.push(intervals[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Chord.prototype = {
|
|
notes : function() {
|
|
var root = this.root;
|
|
return this.voicing().map(function(interval) {
|
|
return root.interval(interval);
|
|
});
|
|
},
|
|
|
|
simple : function() {
|
|
return this.notes().map(function(n) {
|
|
return n.toString(true);
|
|
});
|
|
},
|
|
|
|
bass : function() {
|
|
return this.root.interval(this._voicing[0]);
|
|
},
|
|
|
|
voicing : function(voicing) {
|
|
// Get the voicing
|
|
if (!voicing) {
|
|
return this._voicing;
|
|
}
|
|
|
|
// Set the voicing
|
|
this._voicing = [];
|
|
for (var i = 0, length = voicing.length; i < length; i++) {
|
|
this._voicing[i] = Interval.toCoord(voicing[i]);
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
resetVoicing : function() {
|
|
this._voicing = this.intervals;
|
|
},
|
|
|
|
dominant : function(additional) {
|
|
additional = additional || "";
|
|
return new Chord(this.root.interval("P5"), additional);
|
|
},
|
|
|
|
subdominant : function(additional) {
|
|
additional = additional || "";
|
|
return new Chord(this.root.interval("P4"), additional);
|
|
},
|
|
|
|
parallel : function(additional) {
|
|
additional = additional || "";
|
|
var quality = this.quality();
|
|
|
|
if (this.chordType() !== "triad" || quality === "diminished" ||
|
|
quality === "augmented") {
|
|
throw new Error("Only major/minor triads have parallel chords");
|
|
}
|
|
|
|
if (quality === "major") {
|
|
return new Chord(this.root.interval("m3", "down"), "m");
|
|
} else {
|
|
return new Chord(this.root.interval("m3", "up"));
|
|
}
|
|
},
|
|
|
|
quality : function() {
|
|
var third, fifth, seventh, intervals = this.intervals;
|
|
|
|
for (var i = 0, length = intervals.length; i < length; i++) {
|
|
if (intervals[i].number() === 3) {
|
|
third = intervals[i];
|
|
} else if (intervals[i].number() === 5) {
|
|
fifth = intervals[i];
|
|
} else if (intervals[i].number() === 7) {
|
|
seventh = intervals[i];
|
|
}
|
|
}
|
|
|
|
if (!third) {
|
|
return;
|
|
}
|
|
|
|
third = (third.direction() === "down") ? third.invert() : third;
|
|
third = third.simple().toString();
|
|
|
|
if (fifth) {
|
|
fifth = (fifth.direction === "down") ? fifth.invert() : fifth;
|
|
fifth = fifth.simple().toString();
|
|
}
|
|
|
|
if (seventh) {
|
|
seventh = (seventh.direction === "down") ? seventh.invert() : seventh;
|
|
seventh = seventh.simple().toString();
|
|
}
|
|
|
|
if (third === "M3") {
|
|
if (fifth === "A5") {
|
|
return "augmented";
|
|
} else if (fifth === "P5") {
|
|
return (seventh === "m7") ? "dominant" : "major";
|
|
}
|
|
|
|
return "major";
|
|
} else if (third === "m3") {
|
|
if (fifth === "P5") {
|
|
return "minor";
|
|
} else if (fifth === "d5") {
|
|
return (seventh === "m7") ? "half-diminished" : "diminished";
|
|
}
|
|
|
|
return "minor";
|
|
}
|
|
},
|
|
|
|
chordType : function() { // In need of better name
|
|
var length = this.intervals.length, interval, has, invert, i, name;
|
|
|
|
if (length === 2) {
|
|
return "dyad";
|
|
} else if (length === 3) {
|
|
has = { first : false, third : false, fifth : false };
|
|
for (i = 0; i < length; i++) {
|
|
interval = this.intervals[i];
|
|
invert = interval.invert();
|
|
if (interval.base() in has) {
|
|
has[interval.base()] = true;
|
|
} else if (invert.base() in has) {
|
|
has[invert.base()] = true;
|
|
}
|
|
}
|
|
|
|
name = (has.first && has.third && has.fifth) ? "triad" : "trichord";
|
|
} else if (length === 4) {
|
|
has = { first : false, third : false, fifth : false, seventh : false };
|
|
for (i = 0; i < length; i++) {
|
|
interval = this.intervals[i];
|
|
invert = interval.invert();
|
|
if (interval.base() in has) {
|
|
has[interval.base()] = true;
|
|
} else if (invert.base() in has) {
|
|
has[invert.base()] = true;
|
|
}
|
|
}
|
|
|
|
if (has.first && has.third && has.fifth && has.seventh) {
|
|
name = "tetrad";
|
|
}
|
|
}
|
|
|
|
return name || "unknown";
|
|
},
|
|
|
|
get : function(interval) {
|
|
if (typeof interval === "string" && interval in knowledge.stepNumber) {
|
|
var intervals = this.intervals, i, length;
|
|
|
|
interval = knowledge.stepNumber[interval];
|
|
for (i = 0, length = intervals.length; i < length; i++) {
|
|
if (intervals[i].number() === interval) {
|
|
return this.root.interval(intervals[i]);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
} else {
|
|
throw new Error("Invalid interval name");
|
|
}
|
|
},
|
|
|
|
interval : function(interval) {
|
|
return new Chord(this.root.interval(interval), this.symbol);
|
|
},
|
|
|
|
transpose : function(interval) {
|
|
this.root.transpose(interval);
|
|
this.name = this.root.name().toUpperCase() +
|
|
this.root.accidental() + this.symbol;
|
|
|
|
return this;
|
|
},
|
|
|
|
toString : function() {
|
|
return this.name;
|
|
}
|
|
};
|
|
|
|
module.exports = Chord;
|
|
|
|
},{ "./interval" : 3,"./knowledge" : 4,"./note" : 5,"daccord" : 9 }],3 : [function(require,module,exports){
|
|
var knowledge = require("./knowledge");
|
|
var vector = require("./vector");
|
|
var toCoord = require("interval-coords");
|
|
|
|
function Interval(coord) {
|
|
if (!(this instanceof Interval)) {
|
|
return new Interval(coord);
|
|
}
|
|
this.coord = coord;
|
|
}
|
|
|
|
Interval.prototype = {
|
|
name : function() {
|
|
return knowledge.intervalsIndex[this.number() - 1];
|
|
},
|
|
|
|
semitones : function() {
|
|
return vector.sum(vector.mul(this.coord, [12, 7]));
|
|
},
|
|
|
|
number : function() {
|
|
return Math.abs(this.value());
|
|
},
|
|
|
|
value : function() {
|
|
var without = vector.sub(this.coord,
|
|
vector.mul(knowledge.sharp, Math.floor((this.coord[1] - 2) / 7) + 1))
|
|
, i, val;
|
|
|
|
i = knowledge.intervalFromFifth[without[1] + 5];
|
|
val = knowledge.stepNumber[i] + (without[0] - knowledge.intervals[i][0]) * 7;
|
|
|
|
return (val > 0) ? val : val - 2;
|
|
},
|
|
|
|
type : function() {
|
|
return knowledge.intervals[this.base()][0] <= 1 ? "perfect" : "minor";
|
|
},
|
|
|
|
base : function() {
|
|
var fifth = vector.sub(this.coord, vector.mul(knowledge.sharp, this.qualityValue()))[1], name;
|
|
fifth = this.value() > 0 ? fifth + 5 : -(fifth - 5) % 7;
|
|
fifth = fifth < 0 ? knowledge.intervalFromFifth.length + fifth : fifth;
|
|
|
|
name = knowledge.intervalFromFifth[fifth];
|
|
if (name === "unison" && this.number() >= 8) {
|
|
name = "octave";
|
|
}
|
|
|
|
return name;
|
|
},
|
|
|
|
direction : function(dir) {
|
|
if (dir) {
|
|
var is = this.value() >= 1 ? "up" : "down";
|
|
if (is !== dir) {
|
|
this.coord = vector.mul(this.coord, -1);
|
|
}
|
|
|
|
return this;
|
|
} else {
|
|
return this.value() >= 1 ? "up" : "down";
|
|
}
|
|
},
|
|
|
|
simple : function(ignore) {
|
|
// Get the (upwards) base interval (with quality)
|
|
var simple = knowledge.intervals[this.base()];
|
|
simple = vector.add(simple, vector.mul(knowledge.sharp, this.qualityValue()));
|
|
|
|
// Turn it around if necessary
|
|
if (!ignore) {
|
|
simple = this.direction() === "down" ? vector.mul(simple, -1) : simple;
|
|
}
|
|
|
|
return new Interval(simple);
|
|
},
|
|
|
|
isCompound : function() {
|
|
return this.number() > 8;
|
|
},
|
|
|
|
octaves : function() {
|
|
var without, octaves;
|
|
|
|
if (this.direction() === "up") {
|
|
without = vector.sub(this.coord, vector.mul(knowledge.sharp, this.qualityValue()));
|
|
octaves = without[0] - knowledge.intervals[this.base()][0];
|
|
} else {
|
|
without = vector.sub(this.coord, vector.mul(knowledge.sharp, -this.qualityValue()));
|
|
octaves = -(without[0] + knowledge.intervals[this.base()][0]);
|
|
}
|
|
|
|
return octaves;
|
|
},
|
|
|
|
invert : function() {
|
|
var i = this.base();
|
|
var qual = this.qualityValue();
|
|
var acc = this.type() === "minor" ? -(qual - 1) : -qual;
|
|
var coord = knowledge.intervals[knowledge.intervalsIndex[9 - knowledge.stepNumber[i] - 1]];
|
|
coord = vector.add(coord, vector.mul(knowledge.sharp, acc));
|
|
|
|
return new Interval(coord);
|
|
},
|
|
|
|
quality : function(lng) {
|
|
var quality = knowledge.alterations[this.type()][this.qualityValue() + 2];
|
|
|
|
return lng ? knowledge.qualityLong[quality] : quality;
|
|
},
|
|
|
|
qualityValue : function() {
|
|
if (this.direction() === "down") {
|
|
return Math.floor((-this.coord[1] - 2) / 7) + 1;
|
|
} else {
|
|
return Math.floor((this.coord[1] - 2) / 7) + 1;
|
|
}
|
|
},
|
|
|
|
equal : function(interval) {
|
|
return this.coord[0] === interval.coord[0] &&
|
|
this.coord[1] === interval.coord[1];
|
|
},
|
|
|
|
greater : function(interval) {
|
|
var semi = this.semitones();
|
|
var isemi = interval.semitones();
|
|
|
|
// If equal in absolute size, measure which interval is bigger
|
|
// For example P4 is bigger than A3
|
|
return (semi === isemi) ?
|
|
(this.number() > interval.number()) : (semi > isemi);
|
|
},
|
|
|
|
smaller : function(interval) {
|
|
return !this.equal(interval) && !this.greater(interval);
|
|
},
|
|
|
|
add : function(interval) {
|
|
return new Interval(vector.add(this.coord, interval.coord));
|
|
},
|
|
|
|
toString : function(ignore) {
|
|
// If given true, return the positive value
|
|
var number = ignore ? this.number() : this.value();
|
|
|
|
return this.quality() + number;
|
|
}
|
|
};
|
|
|
|
Interval.toCoord = function(simple) {
|
|
var coord = toCoord(simple);
|
|
if (!coord) {
|
|
throw new Error("Invalid simple format interval");
|
|
}
|
|
|
|
return new Interval(coord);
|
|
};
|
|
|
|
Interval.from = function(from, to) {
|
|
return from.interval(to);
|
|
};
|
|
|
|
Interval.between = function(from, to) {
|
|
return new Interval(vector.sub(to.coord, from.coord));
|
|
};
|
|
|
|
Interval.invert = function(sInterval) {
|
|
return Interval.toCoord(sInterval).invert().toString();
|
|
};
|
|
|
|
module.exports = Interval;
|
|
|
|
},{ "./knowledge" : 4,"./vector" : 8,"interval-coords" : 13 }],4 : [function(require,module,exports){
|
|
// Note coordinates [octave, fifth] relative to C
|
|
module.exports = {
|
|
notes : {
|
|
c : [0, 0],
|
|
d : [-1, 2],
|
|
e : [-2, 4],
|
|
f : [1, -1],
|
|
g : [0, 1],
|
|
a : [-1, 3],
|
|
b : [-2, 5],
|
|
h : [-2, 5]
|
|
},
|
|
|
|
intervals : {
|
|
unison : [0, 0],
|
|
second : [3, -5],
|
|
third : [2, -3],
|
|
fourth : [1, -1],
|
|
fifth : [0, 1],
|
|
sixth : [3, -4],
|
|
seventh : [2, -2],
|
|
octave : [1, 0]
|
|
},
|
|
|
|
intervalFromFifth : ["second", "sixth", "third", "seventh", "fourth",
|
|
"unison", "fifth"],
|
|
|
|
intervalsIndex : ["unison", "second", "third", "fourth", "fifth",
|
|
"sixth", "seventh", "octave", "ninth", "tenth",
|
|
"eleventh", "twelfth", "thirteenth", "fourteenth",
|
|
"fifteenth"],
|
|
|
|
// linaer index to fifth = (2 * index + 1) % 7
|
|
fifths : ["f", "c", "g", "d", "a", "e", "b"],
|
|
accidentals : ["bb", "b", "", "#", "x"],
|
|
|
|
sharp : [-4, 7],
|
|
A4 : [3, 3],
|
|
|
|
durations : {
|
|
"0.25" : "longa",
|
|
"0.5" : "breve",
|
|
"1" : "whole",
|
|
"2" : "half",
|
|
"4" : "quarter",
|
|
"8" : "eighth",
|
|
"16" : "sixteenth",
|
|
"32" : "thirty-second",
|
|
"64" : "sixty-fourth",
|
|
"128" : "hundred-twenty-eighth"
|
|
},
|
|
|
|
qualityLong : {
|
|
P : "perfect",
|
|
M : "major",
|
|
m : "minor",
|
|
A : "augmented",
|
|
AA : "doubly augmented",
|
|
d : "diminished",
|
|
dd : "doubly diminished"
|
|
},
|
|
|
|
alterations : {
|
|
perfect : ["dd", "d", "P", "A", "AA"],
|
|
minor : ["dd", "d", "m", "M", "A", "AA"]
|
|
},
|
|
|
|
symbols : {
|
|
"min" : ["m3", "P5"],
|
|
"m" : ["m3", "P5"],
|
|
"-" : ["m3", "P5"],
|
|
|
|
"M" : ["M3", "P5"],
|
|
"" : ["M3", "P5"],
|
|
|
|
"+" : ["M3", "A5"],
|
|
"aug" : ["M3", "A5"],
|
|
|
|
"dim" : ["m3", "d5"],
|
|
"o" : ["m3", "d5"],
|
|
|
|
"maj" : ["M3", "P5", "M7"],
|
|
"dom" : ["M3", "P5", "m7"],
|
|
"ø" : ["m3", "d5", "m7"],
|
|
|
|
"5" : ["P5"]
|
|
},
|
|
|
|
chordShort : {
|
|
"major" : "M",
|
|
"minor" : "m",
|
|
"augmented" : "aug",
|
|
"diminished" : "dim",
|
|
"half-diminished" : "7b5",
|
|
"power" : "5",
|
|
"dominant" : "7"
|
|
},
|
|
|
|
stepNumber : {
|
|
"unison" : 1,
|
|
"first" : 1,
|
|
"second" : 2,
|
|
"third" : 3,
|
|
"fourth" : 4,
|
|
"fifth" : 5,
|
|
"sixth" : 6,
|
|
"seventh" : 7,
|
|
"octave" : 8,
|
|
"ninth" : 9,
|
|
"eleventh" : 11,
|
|
"thirteenth" : 13
|
|
},
|
|
|
|
// Adjusted Shearer syllables - Chromatic solfege system
|
|
// Some intervals are not provided for. These include:
|
|
// dd2 - Doubly diminished second
|
|
// dd3 - Doubly diminished third
|
|
// AA3 - Doubly augmented third
|
|
// dd6 - Doubly diminished sixth
|
|
// dd7 - Doubly diminished seventh
|
|
// AA7 - Doubly augmented seventh
|
|
intervalSolfege : {
|
|
"dd1" : "daw",
|
|
"d1" : "de",
|
|
"P1" : "do",
|
|
"A1" : "di",
|
|
"AA1" : "dai",
|
|
"d2" : "raw",
|
|
"m2" : "ra",
|
|
"M2" : "re",
|
|
"A2" : "ri",
|
|
"AA2" : "rai",
|
|
"d3" : "maw",
|
|
"m3" : "me",
|
|
"M3" : "mi",
|
|
"A3" : "mai",
|
|
"dd4" : "faw",
|
|
"d4" : "fe",
|
|
"P4" : "fa",
|
|
"A4" : "fi",
|
|
"AA4" : "fai",
|
|
"dd5" : "saw",
|
|
"d5" : "se",
|
|
"P5" : "so",
|
|
"A5" : "si",
|
|
"AA5" : "sai",
|
|
"d6" : "law",
|
|
"m6" : "le",
|
|
"M6" : "la",
|
|
"A6" : "li",
|
|
"AA6" : "lai",
|
|
"d7" : "taw",
|
|
"m7" : "te",
|
|
"M7" : "ti",
|
|
"A7" : "tai",
|
|
"dd8" : "daw",
|
|
"d8" : "de",
|
|
"P8" : "do",
|
|
"A8" : "di",
|
|
"AA8" : "dai"
|
|
}
|
|
};
|
|
|
|
},{}],5 : [function(require,module,exports){
|
|
var scientific = require("scientific-notation");
|
|
var helmholtz = require("helmholtz");
|
|
var knowledge = require("./knowledge");
|
|
var vector = require("./vector");
|
|
var Interval = require("./interval");
|
|
|
|
function pad(str, ch, len) {
|
|
for (; len > 0; len--) {
|
|
str += ch;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
function Note(coord, duration) {
|
|
if (!(this instanceof Note)) {
|
|
return new Note(coord, duration);
|
|
}
|
|
duration = duration || {};
|
|
|
|
this.duration = { value : duration.value || 4, dots : duration.dots || 0 };
|
|
this.coord = coord;
|
|
}
|
|
|
|
Note.prototype = {
|
|
octave : function() {
|
|
return this.coord[0] + knowledge.A4[0] - knowledge.notes[this.name()][0] +
|
|
this.accidentalValue() * 4;
|
|
},
|
|
|
|
name : function() {
|
|
return knowledge.fifths[this.coord[1] + knowledge.A4[1] - this.accidentalValue() * 7 + 1];
|
|
},
|
|
|
|
accidentalValue : function() {
|
|
return Math.round((this.coord[1] + knowledge.A4[1] - 2) / 7);
|
|
},
|
|
|
|
accidental : function() {
|
|
return knowledge.accidentals[this.accidentalValue() + 2];
|
|
},
|
|
|
|
/**
|
|
* Returns the key number of the note
|
|
*/
|
|
key : function(white) {
|
|
if (white) {
|
|
return this.coord[0] * 7 + this.coord[1] * 4 + 29;
|
|
} else {
|
|
return this.coord[0] * 12 + this.coord[1] * 7 + 49;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Returns a number ranging from 0-127 representing a MIDI note value
|
|
*/
|
|
midi : function() {
|
|
return this.key() + 20;
|
|
},
|
|
|
|
/**
|
|
* Calculates and returns the frequency of the note.
|
|
* Optional concert pitch (def. 440)
|
|
*/
|
|
fq : function(concertPitch) {
|
|
concertPitch = concertPitch || 440;
|
|
|
|
return concertPitch *
|
|
Math.pow(2, (this.coord[0] * 12 + this.coord[1] * 7) / 12);
|
|
},
|
|
|
|
/**
|
|
* Returns the pitch class index (chroma) of the note
|
|
*/
|
|
chroma : function() {
|
|
var value = (vector.sum(vector.mul(this.coord, [12, 7])) - 3) % 12;
|
|
|
|
return (value < 0) ? value + 12 : value;
|
|
},
|
|
|
|
interval : function(interval) {
|
|
if (typeof interval === "string") {
|
|
interval = Interval.toCoord(interval);
|
|
}
|
|
|
|
if (interval instanceof Interval) {
|
|
return new Note(vector.add(this.coord, interval.coord));
|
|
} else if (interval instanceof Note) {
|
|
return new Interval(vector.sub(interval.coord, this.coord));
|
|
}
|
|
},
|
|
|
|
transpose : function(interval) {
|
|
this.coord = vector.add(this.coord, interval.coord);
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Returns the Helmholtz notation form of the note (fx C,, d' F# g#'')
|
|
*/
|
|
helmholtz : function() {
|
|
var octave = this.octave();
|
|
var name = this.name();
|
|
name = octave < 3 ? name.toUpperCase() : name.toLowerCase();
|
|
var padchar = octave < 3 ? "," : "'";
|
|
var padcount = octave < 2 ? 2 - octave : octave - 3;
|
|
|
|
return pad(name + this.accidental(), padchar, padcount);
|
|
},
|
|
|
|
/**
|
|
* Returns the scientific notation form of the note (fx E4, Bb3, C#7 etc.)
|
|
*/
|
|
scientific : function() {
|
|
return this.name().toUpperCase() + this.accidental() + this.octave();
|
|
},
|
|
|
|
/**
|
|
* Returns notes that are enharmonic with this note.
|
|
*/
|
|
enharmonics : function(oneaccidental) {
|
|
var key = this.key(), limit = oneaccidental ? 2 : 3;
|
|
|
|
return ["m3", "m2", "m-2", "m-3"]
|
|
.map(this.interval.bind(this))
|
|
.filter(function(note) {
|
|
var acc = note.accidentalValue();
|
|
var diff = key - (note.key() - acc);
|
|
|
|
if (diff < limit && diff > -limit) {
|
|
note.coord = vector.add(note.coord, vector.mul(knowledge.sharp, diff - acc));
|
|
return true;
|
|
}
|
|
});
|
|
},
|
|
|
|
solfege : function(scale, showOctaves) {
|
|
var interval = scale.tonic.interval(this), solfege, stroke, count;
|
|
if (interval.direction() === "down") {
|
|
interval = interval.invert();
|
|
}
|
|
|
|
if (showOctaves) {
|
|
count = (this.key(true) - scale.tonic.key(true)) / 7;
|
|
count = (count >= 0) ? Math.floor(count) : -(Math.ceil(-count));
|
|
stroke = (count >= 0) ? "'" : ",";
|
|
}
|
|
|
|
solfege = knowledge.intervalSolfege[interval.simple(true).toString()];
|
|
return (showOctaves) ? pad(solfege, stroke, Math.abs(count)) : solfege;
|
|
},
|
|
|
|
scaleDegree : function(scale) {
|
|
var inter = scale.tonic.interval(this);
|
|
|
|
// If the direction is down, or we're dealing with an octave - invert it
|
|
if (inter.direction() === "down" ||
|
|
(inter.coord[1] === 0 && inter.coord[0] !== 0)) {
|
|
inter = inter.invert();
|
|
}
|
|
|
|
inter = inter.simple(true).coord;
|
|
|
|
return scale.scale.reduce(function(index, current, i) {
|
|
var coord = Interval.toCoord(current).coord;
|
|
return coord[0] === inter[0] && coord[1] === inter[1] ? i + 1 : index;
|
|
}, 0);
|
|
},
|
|
|
|
/**
|
|
* Returns the name of the duration value,
|
|
* such as 'whole', 'quarter', 'sixteenth' etc.
|
|
*/
|
|
durationName : function() {
|
|
return knowledge.durations[this.duration.value];
|
|
},
|
|
|
|
/**
|
|
* Returns the duration of the note (including dots)
|
|
* in seconds. The first argument is the tempo in beats
|
|
* per minute, the second is the beat unit (i.e. the
|
|
* lower numeral in a time signature).
|
|
*/
|
|
durationInSeconds : function(bpm, beatUnit) {
|
|
var secs = (60 / bpm) / (this.duration.value / 4) / (beatUnit / 4);
|
|
return secs * 2 - secs / Math.pow(2, this.duration.dots);
|
|
},
|
|
|
|
/**
|
|
* Returns the name of the note, with an optional display of octave number
|
|
*/
|
|
toString : function(dont) {
|
|
return this.name() + this.accidental() + (dont ? "" : this.octave());
|
|
}
|
|
};
|
|
|
|
Note.fromString = function(name, dur) {
|
|
var coord = scientific(name);
|
|
if (!coord) {
|
|
coord = helmholtz(name);
|
|
}
|
|
return new Note(coord, dur);
|
|
};
|
|
|
|
Note.fromKey = function(key) {
|
|
var octave = Math.floor((key - 4) / 12);
|
|
var distance = key - (octave * 12) - 4;
|
|
var name = knowledge.fifths[(2 * Math.round(distance / 2) + 1) % 7];
|
|
var note = vector.add(vector.sub(knowledge.notes[name], knowledge.A4), [octave + 1, 0]);
|
|
var diff = (key - 49) - vector.sum(vector.mul(note, [12, 7]));
|
|
|
|
return new Note(diff ? vector.add(note, vector.mul(knowledge.sharp, diff)) : note);
|
|
};
|
|
|
|
Note.fromFrequency = function(fq, concertPitch) {
|
|
var key, cents, originalFq;
|
|
concertPitch = concertPitch || 440;
|
|
|
|
key = 49 + 12 * ((Math.log(fq) - Math.log(concertPitch)) / Math.log(2));
|
|
key = Math.round(key);
|
|
originalFq = concertPitch * Math.pow(2, (key - 49) / 12);
|
|
cents = 1200 * (Math.log(fq / originalFq) / Math.log(2));
|
|
|
|
return { note : Note.fromKey(key), cents : cents };
|
|
};
|
|
|
|
Note.fromMIDI = function(note) {
|
|
return Note.fromKey(note - 20);
|
|
};
|
|
|
|
module.exports = Note;
|
|
|
|
},{ "./interval" : 3,"./knowledge" : 4,"./vector" : 8,"helmholtz" : 10,"scientific-notation" : 14 }],6 : [function(require,module,exports){
|
|
var knowledge = require("./knowledge");
|
|
var Interval = require("./interval");
|
|
|
|
var scales = {
|
|
aeolian : ["P1", "M2", "m3", "P4", "P5", "m6", "m7"],
|
|
blues : ["P1", "m3", "P4", "A4", "P5", "m7"],
|
|
chromatic : ["P1", "m2", "M2", "m3", "M3", "P4", "A4", "P5", "m6", "M6", "m7", "M7"],
|
|
dorian : ["P1", "M2", "m3", "P4", "P5", "M6", "m7"],
|
|
doubleharmonic : ["P1", "m2", "M3", "P4", "P5", "m6", "M7"],
|
|
harmonicminor : ["P1", "M2", "m3", "P4", "P5", "m6", "M7"],
|
|
ionian : ["P1", "M2", "M3", "P4", "P5", "M6", "M7"],
|
|
locrian : ["P1", "m2", "m3", "P4", "d5", "m6", "m7"],
|
|
lydian : ["P1", "M2", "M3", "A4", "P5", "M6", "M7"],
|
|
majorpentatonic : ["P1", "M2", "M3", "P5", "M6"],
|
|
melodicminor : ["P1", "M2", "m3", "P4", "P5", "M6", "M7"],
|
|
minorpentatonic : ["P1", "m3", "P4", "P5", "m7"],
|
|
mixolydian : ["P1", "M2", "M3", "P4", "P5", "M6", "m7"],
|
|
phrygian : ["P1", "m2", "m3", "P4", "P5", "m6", "m7"]
|
|
};
|
|
|
|
// synonyms
|
|
scales.harmonicchromatic = scales.chromatic;
|
|
scales.minor = scales.aeolian;
|
|
scales.major = scales.ionian;
|
|
scales.flamenco = scales.doubleharmonic;
|
|
|
|
function Scale(tonic, scale) {
|
|
if (!(this instanceof Scale)) {
|
|
return new Scale(tonic, scale);
|
|
}
|
|
var scaleName, i;
|
|
if (!("coord" in tonic)) {
|
|
throw new Error("Invalid Tonic");
|
|
}
|
|
|
|
if (typeof scale === "string") {
|
|
scaleName = scale;
|
|
scale = scales[scale];
|
|
if (!scale) {
|
|
throw new Error("Invalid Scale");
|
|
}
|
|
} else {
|
|
for (i in scales) {
|
|
if (scales.hasOwnProperty(i)) {
|
|
if (scales[i].toString() === scale.toString()) {
|
|
scaleName = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.name = scaleName;
|
|
this.tonic = tonic;
|
|
this.scale = scale;
|
|
}
|
|
|
|
Scale.prototype = {
|
|
notes : function() {
|
|
var notes = [];
|
|
|
|
for (var i = 0, length = this.scale.length; i < length; i++) {
|
|
notes.push(this.tonic.interval(this.scale[i]));
|
|
}
|
|
|
|
return notes;
|
|
},
|
|
|
|
simple : function() {
|
|
return this.notes().map(function(n) {
|
|
return n.toString(true);
|
|
});
|
|
},
|
|
|
|
type : function() {
|
|
var length = this.scale.length - 2;
|
|
if (length < 8) {
|
|
return ["di", "tri", "tetra", "penta", "hexa", "hepta", "octa"][length] +
|
|
"tonic";
|
|
}
|
|
},
|
|
|
|
get : function(i) {
|
|
i = (typeof i === "string" && i in knowledge.stepNumber) ? knowledge.stepNumber[i] : i;
|
|
|
|
return this.tonic.interval(this.scale[i - 1]);
|
|
},
|
|
|
|
solfege : function(index, showOctaves) {
|
|
if (index) {
|
|
return this.get(index).solfege(this, showOctaves);
|
|
}
|
|
|
|
return this.notes().map(function(n) {
|
|
return n.solfege(this, showOctaves);
|
|
});
|
|
},
|
|
|
|
interval : function(interval) {
|
|
interval = (typeof interval === "string") ?
|
|
Interval.toCoord(interval) : interval;
|
|
return new Scale(this.tonic.interval(interval), this.scale);
|
|
},
|
|
|
|
transpose : function(interval) {
|
|
var scale = this.interval(interval);
|
|
this.scale = scale.scale;
|
|
this.tonic = scale.tonic;
|
|
|
|
return this;
|
|
}
|
|
};
|
|
|
|
module.exports = Scale;
|
|
|
|
},{ "./interval" : 3,"./knowledge" : 4 }],7 : [function(require,module,exports){
|
|
var knowledge = require("./knowledge");
|
|
|
|
module.exports = function(teoria) {
|
|
var Note = teoria.Note;
|
|
var Chord = teoria.Chord;
|
|
var Scale = teoria.Scale;
|
|
|
|
Note.prototype.chord = function(chord) {
|
|
chord = (chord in knowledge.chordShort) ? knowledge.chordShort[chord] : chord;
|
|
|
|
return new Chord(this, chord);
|
|
};
|
|
|
|
Note.prototype.scale = function(scale) {
|
|
return new Scale(this, scale);
|
|
};
|
|
};
|
|
|
|
},{ "./knowledge" : 4 }],8 : [function(require,module,exports){
|
|
module.exports = {
|
|
add : function(note, interval) {
|
|
return [note[0] + interval[0], note[1] + interval[1]];
|
|
},
|
|
|
|
sub : function(note, interval) {
|
|
return [note[0] - interval[0], note[1] - interval[1]];
|
|
},
|
|
|
|
mul : function(note, interval) {
|
|
if (typeof interval === "number") {
|
|
return [note[0] * interval, note[1] * interval];
|
|
} else {
|
|
return [note[0] * interval[0], note[1] * interval[1]];
|
|
}
|
|
},
|
|
|
|
sum : function(coord) {
|
|
return coord[0] + coord[1];
|
|
}
|
|
};
|
|
|
|
},{}],9 : [function(require,module,exports){
|
|
var SYMBOLS = {
|
|
"m" : ["m3", "P5"],
|
|
"mi" : ["m3", "P5"],
|
|
"min" : ["m3", "P5"],
|
|
"-" : ["m3", "P5"],
|
|
|
|
"M" : ["M3", "P5"],
|
|
"ma" : ["M3", "P5"],
|
|
"" : ["M3", "P5"],
|
|
|
|
"+" : ["M3", "A5"],
|
|
"aug" : ["M3", "A5"],
|
|
|
|
"dim" : ["m3", "d5"],
|
|
"o" : ["m3", "d5"],
|
|
|
|
"maj" : ["M3", "P5", "M7"],
|
|
"dom" : ["M3", "P5", "m7"],
|
|
"ø" : ["m3", "d5", "m7"],
|
|
|
|
"5" : ["P5"],
|
|
|
|
"6/9" : ["M3", "P5", "M6", "M9"]
|
|
};
|
|
|
|
module.exports = function(symbol) {
|
|
var c, parsing = "quality", additionals = [], name, chordLength = 2;
|
|
var notes = ["P1", "M3", "P5", "m7", "M9", "P11", "M13"];
|
|
var explicitMajor = false;
|
|
|
|
function setChord(name) {
|
|
var intervals = SYMBOLS[name];
|
|
for (var i = 0, len = intervals.length; i < len; i++) {
|
|
notes[i + 1] = intervals[i];
|
|
}
|
|
|
|
chordLength = intervals.length;
|
|
}
|
|
|
|
// Remove whitespace, commas and parentheses
|
|
symbol = symbol.replace(/[,\s\(\)]/g, "");
|
|
for (var i = 0, len = symbol.length; i < len; i++) {
|
|
if (!(c = symbol[i])) {
|
|
return;
|
|
}
|
|
|
|
if (parsing === "quality") {
|
|
var sub3 = (i + 2) < len ? symbol.substr(i, 3).toLowerCase() : null;
|
|
var sub2 = (i + 1) < len ? symbol.substr(i, 2).toLowerCase() : null;
|
|
if (sub3 in SYMBOLS) {
|
|
name = sub3;
|
|
} else if (sub2 in SYMBOLS) {
|
|
name = sub2;
|
|
} else if (c in SYMBOLS) {
|
|
name = c;
|
|
} else {
|
|
name = "";
|
|
}
|
|
|
|
if (name) {
|
|
setChord(name);
|
|
}
|
|
|
|
if (name === "M" || name === "ma" || name === "maj") {
|
|
explicitMajor = true;
|
|
}
|
|
|
|
i += name.length - 1;
|
|
parsing = "extension";
|
|
} else if (parsing === "extension") {
|
|
c = (c === "1" && symbol[i + 1]) ? +symbol.substr(i, 2) : +c;
|
|
|
|
if (!isNaN(c) && c !== 6) {
|
|
chordLength = (c - 1) / 2;
|
|
|
|
if (chordLength !== Math.round(chordLength)) {
|
|
return new Error("Invalid interval extension: " + c.toString(10));
|
|
}
|
|
|
|
if (name === "o" || name === "dim") {
|
|
notes[3] = "d7";
|
|
} else if (explicitMajor) {
|
|
notes[3] = "M7";
|
|
}
|
|
|
|
i += c >= 10 ? 1 : 0;
|
|
} else if (c === 6) {
|
|
notes[3] = "M6";
|
|
chordLength = Math.max(3, chordLength);
|
|
} else {
|
|
i -= 1;
|
|
}
|
|
|
|
parsing = "alterations";
|
|
} else if (parsing === "alterations") {
|
|
var alterations = symbol.substr(i).split(/(#|b|add|maj|sus|M)/i),
|
|
next, flat = false, sharp = false;
|
|
|
|
if (alterations.length === 1) {
|
|
return new Error("Invalid alteration");
|
|
} else if (alterations[0].length !== 0) {
|
|
return new Error("Invalid token: '" + alterations[0] + "'");
|
|
}
|
|
|
|
var ignore = false;
|
|
alterations.forEach(function(alt, i, arr) {
|
|
if (ignore || !alt.length) {
|
|
return ignore = false;
|
|
}
|
|
|
|
var next = arr[i + 1], lower = alt.toLowerCase();
|
|
if (alt === "M" || lower === "maj") {
|
|
if (next === "7") {
|
|
ignore = true;
|
|
}
|
|
|
|
chordLength = Math.max(3, chordLength);
|
|
notes[3] = "M7";
|
|
} else if (lower === "sus") {
|
|
var type = "P4";
|
|
if (next === "2" || next === "4") {
|
|
ignore = true;
|
|
|
|
if (next === "2") {
|
|
type = "M2";
|
|
}
|
|
}
|
|
|
|
notes[1] = type; // Replace third with M2 or P4
|
|
} else if (lower === "add") {
|
|
if (next === "9") {
|
|
additionals.push("M9");
|
|
} else if (next === "11") {
|
|
additionals.push("P11");
|
|
} else if (next === "13") {
|
|
additionals.push("M13");
|
|
}
|
|
|
|
ignore = true;
|
|
} else if (lower === "b") {
|
|
flat = true;
|
|
} else if (lower === "#") {
|
|
sharp = true;
|
|
} else {
|
|
var token = +alt, quality, intPos;
|
|
if (isNaN(token) || String(token).length !== alt.length) {
|
|
return new Error("Invalid token: '" + alt + "'");
|
|
}
|
|
|
|
if (token === 6) {
|
|
if (sharp) {
|
|
notes[3] = "A6";
|
|
} else if (flat) {
|
|
notes[3] = "m6";
|
|
} else {
|
|
notes[3] = "M6";
|
|
}
|
|
|
|
chordLength = Math.max(3, chordLength);
|
|
return;
|
|
}
|
|
|
|
// Calculate the position in the 'note' array
|
|
intPos = (token - 1) / 2;
|
|
if (chordLength < intPos) {
|
|
chordLength = intPos;
|
|
}
|
|
|
|
if (token < 5 || token === 7 || intPos !== Math.round(intPos)) {
|
|
return new Error("Invalid interval alteration: " + token);
|
|
}
|
|
|
|
quality = notes[intPos][0];
|
|
|
|
// Alterate the quality of the interval according the accidentals
|
|
if (sharp) {
|
|
if (quality === "d") {
|
|
quality = "m";
|
|
} else if (quality === "m") {
|
|
quality = "M";
|
|
} else if (quality === "M" || quality === "P") {
|
|
quality = "A";
|
|
}
|
|
} else if (flat) {
|
|
if (quality === "A") {
|
|
quality = "M";
|
|
} else if (quality === "M") {
|
|
quality = "m";
|
|
} else if (quality === "m" || quality === "P") {
|
|
quality = "d";
|
|
}
|
|
}
|
|
|
|
sharp = flat = false;
|
|
notes[intPos] = quality + token;
|
|
}
|
|
});
|
|
parsing = "ended";
|
|
} else if (parsing === "ended") {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return notes.slice(0, chordLength + 1).concat(additionals);
|
|
};
|
|
|
|
},{}],10 : [function(require,module,exports){
|
|
var coords = require("notecoord");
|
|
var accval = require("accidental-value");
|
|
|
|
module.exports = function helmholtz(name) {
|
|
var name = name.replace(/\u2032/g, "'").replace(/\u0375/g, ",");
|
|
var parts = name.match(/^(,*)([a-h])(x|#|bb|b?)([,\']*)$/i);
|
|
|
|
if (!parts || name !== parts[0]) {
|
|
throw new Error("Invalid formatting");
|
|
}
|
|
|
|
var note = parts[2];
|
|
var octaveFirst = parts[1];
|
|
var octaveLast = parts[4];
|
|
var lower = note === note.toLowerCase();
|
|
var octave;
|
|
|
|
if (octaveFirst) {
|
|
if (lower) {
|
|
throw new Error("Invalid formatting - found commas before lowercase note");
|
|
}
|
|
|
|
octave = 2 - octaveFirst.length;
|
|
} else if (octaveLast) {
|
|
if (octaveLast.match(/^'+$/) && lower) {
|
|
octave = 3 + octaveLast.length;
|
|
} else if (octaveLast.match(/^,+$/) && !lower) {
|
|
octave = 2 - octaveLast.length;
|
|
} else {
|
|
throw new Error("Invalid formatting - mismatch between octave " +
|
|
"indicator and letter case");
|
|
}
|
|
} else {
|
|
octave = lower ? 3 : 2;
|
|
}
|
|
|
|
var accidentalValue = accval.interval(parts[3].toLowerCase());
|
|
var coord = coords(note.toLowerCase());
|
|
|
|
coord[0] += octave;
|
|
coord[0] += accidentalValue[0] - coords.A4[0];
|
|
coord[1] += accidentalValue[1] - coords.A4[1];
|
|
|
|
return coord;
|
|
};
|
|
|
|
},{ "accidental-value" : 11,"notecoord" : 12 }],11 : [function(require,module,exports){
|
|
var accidentalValues = {
|
|
"bb" : -2,
|
|
"b" : -1,
|
|
"" : 0,
|
|
"#" : 1,
|
|
"x" : 2
|
|
};
|
|
|
|
module.exports = function accidentalNumber(acc) {
|
|
return accidentalValues[acc];
|
|
};
|
|
|
|
module.exports.interval = function accidentalInterval(acc) {
|
|
var val = accidentalValues[acc];
|
|
return [-4 * val, 7 * val];
|
|
};
|
|
|
|
},{}],12 : [function(require,module,exports){
|
|
// First coord is octaves, second is fifths. Distances are relative to c
|
|
var notes = {
|
|
c : [0, 0],
|
|
d : [-1, 2],
|
|
e : [-2, 4],
|
|
f : [1, -1],
|
|
g : [0, 1],
|
|
a : [-1, 3],
|
|
b : [-2, 5],
|
|
h : [-2, 5]
|
|
};
|
|
|
|
module.exports = function(name) {
|
|
return name in notes ? [notes[name][0], notes[name][1]] : null;
|
|
};
|
|
|
|
module.exports.notes = notes;
|
|
module.exports.A4 = [3, 3]; // Relative to C0 (scientic notation, ~16.35Hz)
|
|
module.exports.sharp = [-4, 7];
|
|
|
|
},{}],13 : [function(require,module,exports){
|
|
var pattern = /^(AA|A|P|M|m|d|dd)(-?\d+)$/;
|
|
|
|
// The interval it takes to raise a note a semitone
|
|
var sharp = [-4, 7];
|
|
|
|
var pAlts = ["dd", "d", "P", "A", "AA"];
|
|
var mAlts = ["dd", "d", "m", "M", "A", "AA"];
|
|
|
|
var baseIntervals = [
|
|
[0, 0],
|
|
[3, -5],
|
|
[2, -3],
|
|
[1, -1],
|
|
[0, 1],
|
|
[3, -4],
|
|
[2, -2],
|
|
[1, 0]
|
|
];
|
|
|
|
module.exports = function(simple) {
|
|
var parser = simple.match(pattern);
|
|
if (!parser) {
|
|
return null;
|
|
}
|
|
|
|
var quality = parser[1];
|
|
var number = +parser[2];
|
|
var sign = number < 0 ? -1 : 1;
|
|
|
|
number = sign < 0 ? -number : number;
|
|
|
|
var lower = number > 8 ? (number % 7 || 7) : number;
|
|
var octaves = (number - lower) / 7;
|
|
|
|
var base = baseIntervals[lower - 1];
|
|
var alts = base[0] <= 1 ? pAlts : mAlts;
|
|
var alt = alts.indexOf(quality) - 2;
|
|
|
|
// this happens, if the alteration wasn't suitable for this type
|
|
// of interval, such as P2 or M5 (no "perfect second" or "major fifth")
|
|
if (alt === -3) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
sign * (base[0] + octaves + sharp[0] * alt),
|
|
sign * (base[1] + sharp[1] * alt)
|
|
];
|
|
};
|
|
|
|
// Copy to avoid overwriting internal base intervals
|
|
module.exports.coords = baseIntervals.slice(0);
|
|
|
|
},{}],14 : [function(require,module,exports){
|
|
var coords = require("notecoord");
|
|
var accval = require("accidental-value");
|
|
|
|
module.exports = function scientific(name) {
|
|
var format = /^([a-h])(x|#|bb|b?)(-?\d*)/i;
|
|
|
|
parser = name.match(format);
|
|
if (!(parser && name === parser[0] && parser[3].length)) {
|
|
return;
|
|
}
|
|
|
|
var noteName = parser[1];
|
|
var octave = +parser[3];
|
|
var accidental = parser[2].length ? parser[2].toLowerCase() : "";
|
|
|
|
var accidentalValue = accval.interval(accidental);
|
|
var coord = coords(noteName.toLowerCase());
|
|
|
|
coord[0] += octave;
|
|
coord[0] += accidentalValue[0] - coords.A4[0];
|
|
coord[1] += accidentalValue[1] - coords.A4[1];
|
|
|
|
return coord;
|
|
};
|
|
|
|
},{ "accidental-value" : 15,"notecoord" : 16 }],15 : [function(require,module,exports){
|
|
arguments[4][11][0].apply(exports,arguments);
|
|
},{ "dup" : 11 }],16 : [function(require,module,exports){
|
|
arguments[4][12][0].apply(exports,arguments);
|
|
},{ "dup" : 12 }] },{},[1])(1);
|
|
});
|