mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-16 16:48:00 +00:00
1366 lines
No EOL
36 KiB
JavaScript
1366 lines
No EOL
36 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)
|
|
}); |