From 1fb7ea649ed022433206101510c261ffccabf574 Mon Sep 17 00:00:00 2001 From: Jakob Miland Date: Mon, 17 Jun 2013 11:47:46 +0200 Subject: [PATCH] Remove build files from repository --- .gitignore | 3 + dist/teoria.js | 1374 -------------------------------------------- dist/teoria.min.js | 1 - 3 files changed, 3 insertions(+), 1375 deletions(-) delete mode 100644 dist/teoria.js delete mode 100644 dist/teoria.min.js diff --git a/.gitignore b/.gitignore index 23c47d2..084b986 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ # Ignore node modules node_modules/ +# Ignore build files +dist/ + # Ignore my sandbox file index.html diff --git a/dist/teoria.js b/dist/teoria.js deleted file mode 100644 index d40a1c5..0000000 --- a/dist/teoria.js +++ /dev/null @@ -1,1374 +0,0 @@ -/*jshint unused:false */ - -// Teoria.js -// http://saebekassebil.github.com/teoria -// Copyright Jakob Miland (saebekassebil) -// Teoria may be freely distributed under the MIT License. - -(function teoriaClosure() { - 'use strict'; - - var teoria = {}; - - var kNotes = { - 'c': { - name: 'c', - distance: 0, - index: 0 - }, - 'd': { - name: 'd', - distance: 2, - index: 1 - }, - 'e': { - name: 'e', - distance: 4, - index: 2 - }, - 'f': { - name: 'f', - distance: 5, - index: 3 - }, - 'g': { - name: 'g', - distance: 7, - index: 4 - }, - 'a': { - name: 'a', - distance: 9, - index: 5 - }, - 'b': { - name: 'b', - distance: 11, - index: 6 - }, - 'h': { - name: 'h', - distance: 11, - index: 6 - } - }; - - var kNoteIndex = ['c', 'd', 'e', 'f', 'g', 'a', 'b']; - - var kDurations = { - '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' - }; - - var kIntervals = [{ - name: 'first', - quality: 'perfect', - size: 0 - }, { - name: 'second', - quality: 'minor', - size: 1 - }, { - name: 'third', - quality: 'minor', - size: 3 - }, { - name: 'fourth', - quality: 'perfect', - size: 5 - }, { - name: 'fifth', - quality: 'perfect', - size: 7 - }, { - name: 'sixth', - quality: 'minor', - size: 8 - }, { - name: 'seventh', - quality: 'minor', - size: 10 - }, { - name: 'octave', - quality: 'perfect', - size: 12 - }]; - - var kIntervalIndex = { - 'first': 0, 'second': 1, 'third': 2, 'fourth': 3, - 'fifth': 4, 'sixth': 5, 'seventh': 6, 'octave': 7, - 'ninth': 8, 'tenth': 9, 'eleventh': 10, 'twelfth': 11, - 'thirteenth': 12, 'fourteenth': 13, 'fifteenth': 14 - }; - - var kQualityLong = { - 'P': 'perfect', - 'M': 'major', - 'm': 'minor', - '-': 'minor', - 'A': 'augmented', - '+': 'augmented', - 'AA': 'doubly augmented', - 'd': 'diminished', - 'dd': 'doubly diminished', - - 'min': 'minor', - 'aug': 'augmented', - 'dim': 'diminished' - }; - - var kQualityTemp = { - 'perfect': 'P', - 'major': 'M', - 'minor': 'm', - 'augmented': 'A', - 'doubly augmented': 'AA', - 'diminished': 'd', - 'doubly diminished': 'dd' - }; - - var kValidQualities = { - perfect: { - 'doubly diminished': -2, - diminished: -1, - perfect: 0, - augmented: 1, - 'doubly augmented': 2 - }, - - minor: { - 'doubly diminished': -2, - diminished: -1, - minor: 0, - major: 1, - augmented: 2, - 'doubly augmented': 3 - } - }; - - var kQualityInversion = { - 'perfect': 'perfect', - 'major': 'minor', - 'minor': 'major', - 'augmented': 'diminished', - 'doubly augmented': 'doubly diminished', - 'diminished': 'augmented', - 'doubly diminished': 'doubly augmented' - }; - - var kAlterations = { - perfect: ['doubly diminished', 'diminished', 'perfect', - 'augmented', 'doubly augmented'], - - minor: ['doubly diminished', 'diminished', 'minor', - 'major', 'augmented', 'doubly augmented'] - }; - - var kSymbols = { - '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'] - }; - - var kChordShort = { - 'major': 'M', - 'minor': 'm', - 'augmented': 'aug', - 'diminished': 'dim', - 'half-diminished': '7b5', - 'power': '5', - 'dominant': '7' - }; - - var kAccidentalSign = { - '-2': 'bb', - '-1': 'b', - '0': '', - '1': '#', - '2': 'x' - }; - - var kAccidentalValue = { - 'bb': -2, - 'b': -1, - '#': 1, - 'x': 2 - }; - - var kStepNumber = { - 'first': '1', - 'tonic': '1', - 'second': '2', - 'third': '3', - 'fourth': '4', - 'fifth': '5', - 'sixth': '6', - 'seventh': '7', - '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 - var kIntervalSolfege = { - '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' - }; - /** - * getDistance, returns the distance in semitones between two notes - */ - function getDistance(from, to) { - from = kNotes[from]; - to = kNotes[to]; - if (from.distance > to.distance) { - return (to.distance + 12) - from.distance; - } else { - return to.distance - from.distance; - } - } - - function pad(str, ch, len) { - for (; len > 0; len--) { - str += ch; - } - - return str; - } - - // teoria.note namespace - All notes should be instantiated - // through this function. - teoria.note = function(name, duration) { - return new TeoriaNote(name, duration); - }; - - teoria.note.fromKey = function(key) { - var octave = Math.floor((key - 4) / 12); - var distance = key - (octave * 12) - 4; - var note = kNotes[kNoteIndex[Math.round(distance / 2)]]; - var name = note.name; - if (note.distance < distance) { - name += '#'; - } else if (note.distance > distance) { - name += 'b'; - } - - return teoria.note(name + (octave + 1)); - }; - - teoria.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: teoria.note.fromKey(key), cents: cents}; - }; - - teoria.note.fromMIDI = function(note) { - return teoria.note.fromKey(note - 20); - }; - - // teoria.chord namespace - All chords should be instantiated - // through this function. - teoria.chord = function(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 TeoriaChord(teoria.note(root[0].toLowerCase() + octave), - name.substr(root[0].length)); - } - } else if (name instanceof TeoriaNote) { - return new TeoriaChord(name, symbol || ''); - } - - throw new Error('Invalid Chord. Couldn\'t find note name'); - }; - - /** - * teoria.interval - * - * Sugar function for #from and #between methods, with the possibility to - * declare a interval by its string name: P8, M3, m7 etc. - */ - teoria.interval = function(from, to, direction) { - var quality, intervalNumber, interval, match; - - // Construct a TeoriaInterval object from string representation - if (typeof from === 'string') { - match = from.match(/^(AA|A|P|M|m|d|dd)(-?\d+)$/); - if (!match) { - throw new Error('Invalid string-interval format'); - } - - quality = kQualityLong[match[1]]; - intervalNumber = parseInt(match[2], 10); - - // Uses the second argument 'to', as direction - direction = to === 'down' || intervalNumber < 0 ? 'down' : 'up'; - - return new TeoriaInterval(Math.abs(intervalNumber), quality, direction); - } - - if (typeof to === 'string' && from instanceof TeoriaNote) { - interval = teoria.interval(to, direction); - - return teoria.interval.from(from, interval); - } else if (to instanceof TeoriaNote && from instanceof TeoriaNote) { - return teoria.interval.between(from, to); - } else { - throw new Error('Invalid parameters'); - } - }; - - /** - * Returns the note from a given note (from), with a given interval (to) - */ - teoria.interval.from = function(from, to) { - var note, diff, octave, index, dist, intval, dir; - dir = (to.direction === 'down') ? -1 : 1; - - intval = to.simpleInterval - 1; - intval = dir * intval; - - index = kNotes[from.name].index + intval; - - if (index > kNoteIndex.length - 1) { - index = index - kNoteIndex.length; - } else if (index < 0) { - index = index + kNoteIndex.length; - } - - note = kNoteIndex[index]; - dist = getDistance(from.name, note); - - if (dir > 0) { - diff = to.simpleIntervalType.size + to.qualityValue() - dist; - } else { - diff = getDistance(note, from.name) - - (to.simpleIntervalType.size + to.qualityValue()); - } - diff += from.accidental.value; - - octave = Math.floor((from.key() - from.accidental.value + dist - 4) / 12); - octave += 1 + dir * to.compoundOctaves; - - if (diff >= 10) { - diff -= 12; - } else if (diff <= -10) { - diff += 12; - } - - if (to.simpleInterval === 8) { - octave += dir; - } else if (dir < 0) { - octave--; - } - - note += kAccidentalSign[diff]; - return teoria.note(note + octave.toString(10)); - }; - - /** - * Returns the interval between two instances of teoria.note - */ - teoria.interval.between = function(from, to) { - var semitones, interval, intervalInt, quality, - alteration, direction = 'up', dir = 1; - - semitones = to.key() - from.key(); - intervalInt = to.key(true) - from.key(true); - - if (intervalInt < 0) { - intervalInt = -intervalInt; - direction = 'down'; - dir = -1; - } - - interval = kIntervals[intervalInt % 7]; - alteration = kAlterations[interval.quality]; - quality = alteration[(dir * semitones - interval.size + 2) % 12]; - - return new TeoriaInterval(intervalInt + 1, quality, direction); - }; - - teoria.interval.invert = function(sInterval) { - return teoria.interval(sInterval).invert().toString(); - }; - - // teoria.scale namespace - Scales are constructed through this function. - teoria.scale = function(tonic, scale) { - if (!(tonic instanceof TeoriaNote)) { - tonic = teoria.note(tonic); - } - - return new TeoriaScale(tonic, scale); - }; - - teoria.scale.scales = {}; - - /** - * TeoriaNote - teoria.note - the note object - * - * This object is the representation of a note. - * The constructor must be called with a name, - * and optionally a duration argument. - * The first parameter (name) can be specified in either - * scientific notation (name+accidentals+octave). Fx: - * A4 - Cb3 - D#8 - Hbb - etc. - * Or in the Helmholtz notation: - * C,, - f#'' - d - Eb - etc. - * The second argument must be an object literal, with a - * 'value' property and/or a 'dots' property. By default, - * the duration value is 4 (quarter note) and dots is 0. - */ - function TeoriaNote(name, duration) { - if (typeof name !== 'string') { - return null; - } - - duration = duration || {}; - - this.name = name; - this.duration = {value: duration.value || 4, dots: duration.dots || 0}; - this.accidental = {value: 0, sign: ''}; - var scientific = /^([a-h])(x|#|bb|b?)(-?\d*)/i; - var helmholtz = /^([a-h])(x|#|bb|b?)([,\']*)$/i; - var accidentalSign, accidentalValue, noteName, octave; - - // Start trying to parse scientific notation - var parser = name.match(scientific); - if (parser && name === parser[0] && parser[3].length !== 0) { // Scientific - noteName = parser[1].toLowerCase(); - octave = parseInt(parser[3], 10); - - if (parser[2].length > 0) { - accidentalSign = parser[2].toLowerCase(); - accidentalValue = kAccidentalValue[parser[2]]; - } - } else { // Helmholtz Notation - name = name.replace(/\u2032/g, "'").replace(/\u0375/g, ','); - - parser = name.match(helmholtz); - if (!parser || name !== parser[0]) { - throw new Error('Invalid note format'); - } - - noteName = parser[1]; - octave = parser[3]; - if (parser[2].length > 0) { - accidentalSign = parser[2].toLowerCase(); - accidentalValue = kAccidentalValue[parser[2]]; - } - - if (octave.length === 0) { // no octave symbols - octave = (noteName === noteName.toLowerCase()) ? 3 : 2; - } else { - if (octave.match(/^'+$/)) { - if (noteName === noteName.toUpperCase()) { // If upper-case - throw new Error('Format must respect the Helmholtz notation'); - } - - octave = 3 + octave.length; - } else if (octave.match(/^,+$/)) { - if (noteName === noteName.toLowerCase()) { // If lower-case - throw new Error('Format must respect the Helmholtz notation'); - } - - octave = 2 - octave.length; - } else { - throw new Error('Invalid characters after note name.'); - } - } - } - - this.name = noteName.toLowerCase(); - this.octave = octave; - - if (accidentalSign) { - this.accidental.value = accidentalValue; - this.accidental.sign = accidentalSign; - } - } - - TeoriaNote.prototype = { - /** - * Returns the key number of the note - */ - key: function(whitenotes) { - var noteValue; - if (whitenotes) { - noteValue = Math.ceil(kNotes[this.name].distance / 2); - return (this.octave - 1) * 7 + 3 + noteValue; - } else { - noteValue = kNotes[this.name].distance + this.accidental.value; - return (this.octave - 1) * 12 + 4 + noteValue; - } - }, - - /** - * 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.key() - 49) / 12); - }, - - /** - * Returns the pitch class index (chroma) of the note - */ - chroma: function() { - var value = (kNotes[this.name].distance + this.accidental.value) % 12; - return (value < 0) ? value + 12 : value; - }, - - /** - * Sugar function for teoria.scale(note, scale) - */ - scale: function(scale) { - return teoria.scale(this, scale); - }, - - /** - * Sugar function for teoria.interval(note, interval[, direction]) - */ - interval: function(interval, direction) { - return teoria.interval(this, interval, direction); - }, - - /** - * Transposes the note, returned by TeoriaNote#interval - */ - transpose: function(interval, direction) { - var note = teoria.interval(this, interval, direction); - this.name = note.name; - this.octave = note.octave; - this.accidental = note.accidental; - - return this; - }, - - /** - * Returns a TeoriaChord object with this note as root - */ - chord: function(chord) { - chord = (chord in kChordShort) ? kChordShort[chord] : chord; - - return new TeoriaChord(this, chord); - }, - - /** - * Returns the Helmholtz notation form of the note (fx C,, d' F# g#'') - */ - helmholtz: function() { - var name = (this.octave < 3) ? this.name.toUpperCase() : - this.name.toLowerCase(); - var paddingChar = (this.octave < 3) ? ',' : '\''; - var paddingCount = (this.octave < 2) ? 2 - this.octave : this.octave - 3; - - return pad(name + this.accidental.sign, paddingChar, paddingCount); - }, - - /** - * Returns the scientific notation form of the note (fx E4, Bb3, C#7 etc.) - */ - scientific: function() { - return this.name.toUpperCase() + this.accidental.sign + this.octave; - }, - - /** - * Returns notes that are enharmonic with this note. - */ - enharmonics: function() { - var enharmonics = [], key = this.key(), - upper = this.interval('m2', 'up'), lower = this.interval('m2', 'down'); - var upperKey = upper.key() - upper.accidental.value; - var lowerKey = lower.key() - lower.accidental.value; - var diff = key - upperKey; - if (diff < 3 && diff > -3) { - upper.accidental = {value: diff, sign: kAccidentalSign[diff]}; - enharmonics.push(upper); - } - - diff = key - lowerKey; - if (diff < 3 && diff > -3) { - lower.accidental = {value: diff, sign: kAccidentalSign[diff]}; - enharmonics.push(lower); - } - - return enharmonics; - }, - - solfege: function(scale, showOctaves) { - if (!(scale instanceof TeoriaScale)) { - throw new Error('Invalid Scale'); - } - - 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 = kIntervalSolfege[interval.simple(true)]; - return (showOctaves) ? pad(solfege, stroke, Math.abs(count)) : solfege; - }, - - /** - * Returns the name of the duration value, - * such as 'whole', 'quarter', 'sixteenth' etc. - */ - durationName: function() { - return kDurations[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 degree of this note in a given scale - * If the scale doesn't contain this note, the scale degree - * will be returned as 0 allowing for expressions such as: - * if (teoria.note('a').scaleDegree(teoria.scale('a', 'major'))) { - * ... - * } - * - * as 0 evaluates to false in boolean context - **/ - scaleDegree: function(scale) { - var interval = scale.tonic.interval(this); - interval = (interval.direction === 'down' || - interval.simpleInterval === 8) ? interval.invert() : interval; - - return scale.scale.indexOf(interval.simple(true)) + 1; - }, - - /** - * Returns the name of the note, with an optional display of octave number - */ - toString: function(dontShow) { - var octave = dontShow ? '' : this.octave; - return this.name.toLowerCase() + this.accidental.sign + octave; - } - }; - - - function TeoriaInterval(intervalNum, quality, direction) { - var simple = (intervalNum >= 8 && intervalNum % 7 === 1) ? - intervalNum % 7 * 8 : ((intervalNum - 1) % 7) + 1; - var compoundOctaves = Math.ceil((intervalNum - simple) / 8); - var simpleIntervalType = kIntervals[simple - 1]; - - - if (!(quality in kValidQualities[simpleIntervalType.quality])) { - throw new Error('Invalid interval quality'); - } - - this.interval = intervalNum; - this.quality = quality; - this.direction = direction === 'down' ? 'down' : 'up'; - this.simpleInterval = simple; - this.simpleIntervalType = simpleIntervalType; - this.compoundOctaves = compoundOctaves; - } - - TeoriaInterval.prototype = { - semitones: function() { - return this.simpleIntervalType.size + this.qualityValue() + - this.compoundOctaves * 12; - }, - - simple: function(ignore) { - var intval = this.simpleInterval; - intval = (this.direction === 'down' && !ignore) ? -intval : intval; - - return kQualityTemp[this.quality] + intval.toString(); - }, - - compound: function(ignore) { - var intval = this.simpleInterval + this.compoundOctaves * 7; - intval = (this.direction === 'down' && !ignore) ? -intval : intval; - - return kQualityTemp[this.quality] + intval.toString(); - }, - - isCompound: function() { - return this.compoundOctaves > 0; - }, - - invert: function() { - var intervalNumber = this.simpleInterval; - - intervalNumber = 9 - intervalNumber; - - return new TeoriaInterval(intervalNumber, - kQualityInversion[this.quality], this.direction); - }, - - qualityValue: function() { - var defQuality = this.simpleIntervalType.quality, quality = this.quality; - - return kValidQualities[defQuality][quality]; - }, - - equal: function(interval) { - return this.interval === interval.interval && - this.quality === interval.quality; - }, - - greater: function(interval) { - var thisSemitones = this.semitones(); - var thatSemitones = interval.semitones(); - - // If equal in absolute size, measure which interval is bigger - // For example P4 is bigger than A3 - return (thisSemitones === thatSemitones) ? - (this.interval > interval.interval) : (thisSemitones > thatSemitones); - }, - - smaller: function(interval) { - return !this.equal(interval) && !this.greater(interval); - }, - - toString: function() { - return this.compound(); - } - }; - - - function TeoriaChord(root, name) { - if (!(root instanceof TeoriaNote)) { - return null; - } - - name = name || ''; - this.name = root.name.toUpperCase() + root.accidental.sign + name; - this.symbol = name; - this.root = root; - this.intervals = []; - this._voicing = []; - - var i, length, c, strQuality, parsing = 'quality', additionals = [], - notes = ['P1', 'M3', 'P5', 'm7', 'M9', 'P11', 'M13'], - chordLength = 2, bass, symbol; - - function setChord(intervals) { - for (var n = 0, chordl = intervals.length; n < chordl; n++) { - notes[n + 1] = intervals[n]; - } - - chordLength = intervals.length; - } - - // Remove whitespace, commas and parentheses - name = name.replace(/[,\s\(\)]/g, ''); - bass = name.split('/'); - if (bass.length === 2) { - name = bass[0]; - bass = bass[1]; - } else { - bass = null; - } - - for (i = 0, length = name.length; i < length; i++) { - if (!(c = name[i])) { - break; - } - - switch (parsing) { - // Parses for the "base" chord, either a triad or a seventh chord - case 'quality': - strQuality = ((i + 3) <= length) ? name.substr(i, 3) : null; - symbol = (strQuality in kSymbols) ? - strQuality : (c in kSymbols) ? c : ''; - - setChord(kSymbols[symbol]); - - i += symbol.length - 1; - parsing = 'extension'; - break; - - // Parses for the top interval or a pure sixth - case 'extension': - c = (c === '1' && name[i + 1]) ? - parseFloat(name.substr(i, 2)) : parseFloat(c); - - if (!isNaN(c) && c !== 6) { - chordLength = (c - 1) / 2; - - if (chordLength !== Math.round(chordLength)) { - throw new Error('Invalid interval extension: ' + c.toString(10)); - } - - // Special care for diminished chords - if (symbol === 'o' || symbol === 'dim') { - notes[3] = 'd7'; - } - - i += String(c).length - 1; - } else if (c === 6) { - notes[3] = 'M6'; - chordLength = (chordLength < 3) ? 3 : chordLength; - } else { - i -= 1; - } - - parsing = 'alterations'; - break; - - // Parses for possible alterations of intervals (#5, b9, etc.) - case 'alterations': - var alterations = name.substr(i).split(/(#|b|add|maj|sus|M)/), - next, flat = false, sharp = false; - - if (alterations.length === 1) { - throw new Error('Invalid alterations'); - } else if (alterations[0].length !== 0) { - throw new Error('Invalid token: \'' + alterations[0] + '\''); - } - - for (var a = 1, aLength = alterations.length; a < aLength; a++) { - next = alterations[a + 1]; - - switch (alterations[a]) { - case 'M': - case 'maj': - chordLength = (chordLength < 3) ? 3 : chordLength; - - if (next === '7') { // Ignore the seventh, that is already implied - a++; - } - - notes[3] = 'M7'; - break; - - case 'sus': - var type = 'P4'; - if (next === '2' || next === '4') { - a++; - - if (next === '2') { - type = 'M2'; - } - } - - notes[1] = type; // Replace third with M2 or P4 - break; - - case 'add': - if (next && !isNaN(+next)) { - if (next === '9') { - additionals.push('M9'); - } else if (next === '11') { - additionals.push('P11'); - } else if (next === '13') { - additionals.push('M13'); - } - - a += next.length; - } - break; - - case 'b': - flat = true; - break; - - case '#': - sharp = true; - break; - - default: - if (alterations[a].length === 0) { - break; - } - - var token = +alterations[a], quality, intPos; - if (isNaN(token) || - String(token).length !== alterations[a].length) { - throw new Error('Invalid token: \'' + alterations[a] + '\''); - } - - if (token === 6) { - if (sharp) { - notes[3] = 'A6'; - } else if (flat) { - notes[3] = 'm6'; - } else { - notes[3] = 'M6'; - } - - chordLength = (chordLength < 3) ? 3 : chordLength; - continue; - } - - // 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)) { - throw 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; - break; - } - } - - parsing = 'ended'; - break; - } - - if (parsing === 'ended') { - break; - } - } - - this.intervals = notes - .slice(0, chordLength + 1) - .concat(additionals) - .map(function(i) { return teoria.interval(i); }); - - for (i = 0, length = this.intervals.length; i < length; i++) { - this._voicing[i] = this.intervals[i]; - } - - if (bass) { - var intervals = this.intervals, bassInterval, inserted = 0, note; - // Make sure the bass is atop of the root note - note = teoria.note(bass + (root.octave + 1)); - - bassInterval = teoria.interval.between(root, note); - bass = bassInterval.simpleInterval; - - if (bassInterval.direction === 'up') { - bassInterval = bassInterval.invert(); - bassInterval.direction = 'down'; - } - - this._voicing = [bassInterval]; - for (i = 0; i < length; i++) { - if (intervals[i].interval === bass) { - continue; - } - - inserted++; - this._voicing[inserted] = intervals[i]; - } - } - } - - TeoriaChord.prototype = { - notes: function() { - var voicing = this.voicing(), notes = []; - - for (var i = 0, length = voicing.length; i < length; i++) { - notes.push(teoria.interval.from(this.root, voicing[i])); - } - - return notes; - }, - - 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] = teoria.interval(voicing[i]); - } - - return this; - }, - - resetVoicing: function() { - this._voicing = this.intervals; - }, - - dominant: function(additional) { - additional = additional || ''; - return new TeoriaChord(this.root.interval('P5'), additional); - }, - - subdominant: function(additional) { - additional = additional || ''; - return new TeoriaChord(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 TeoriaChord(this.root.interval('m3', 'down'), 'm'); - } else { - return new TeoriaChord(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].interval === 3) { - third = intervals[i]; - } else if (intervals[i].interval === 5) { - fifth = intervals[i]; - } else if (intervals[i].interval === 7) { - seventh = intervals[i]; - } - } - - if (!third) { - return; - } - - third = (third.direction === 'down') ? third.invert() : third; - third = third.simple(); - - if (fifth) { - fifth = (fifth.direction === 'down') ? fifth.invert() : fifth; - fifth = fifth.simple(); - } - - if (seventh) { - seventh = (seventh.direction === 'down') ? seventh.invert() : seventh; - seventh = seventh.simple(); - } - - 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.simpleIntervalType.name in has) { - has[interval.simpleIntervalType.name] = true; - } else if (invert.simpleIntervalType.name in has) { - has[invert.simpleIntervalType.name] = 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.simpleIntervalType.name in has) { - has[interval.simpleIntervalType.name] = true; - } else if (invert.simpleIntervalType.name in has) { - has[invert.simpleIntervalType.name] = true; - } - } - - if (has.first && has.third && has.fifth && has.seventh) { - name = 'tetrad'; - } - } - - return name || 'unknown'; - }, - - get: function(interval) { - if (typeof interval === 'string' && interval in kStepNumber) { - var intervals = this.intervals, i, length; - - interval = kStepNumber[interval]; - for (i = 0, length = intervals.length; i < length; i++) { - if (intervals[i].interval === +interval) { - return teoria.interval.from(this.root, intervals[i]); - } - } - - return null; - } else { - throw new Error('Invalid interval name'); - } - }, - - interval: function(interval, direction) { - return new TeoriaChord(this.root.interval(interval, direction), - this.symbol); - }, - - transpose: function(interval, direction) { - this.root.transpose(interval, direction); - this.name = this.root.name.toUpperCase() + - this.root.accidental.sign + this.symbol; - - return this; - }, - - toString: function() { - return this.name; - } - }; - - - function TeoriaScale(tonic, scale) { - var scaleName, i, length; - - if (!(tonic instanceof TeoriaNote)) { - throw new Error('Invalid Tonic'); - } - - if (typeof scale === 'string') { - scaleName = scale; - scale = teoria.scale.scales[scale]; - if (!scale) { - throw new Error('Invalid Scale'); - } - } else { - for (i in teoria.scale.scales) { - if (teoria.scale.scales.hasOwnProperty(i)) { - if (teoria.scale.scales[i].toString() === scale.toString()) { - scaleName = i; - break; - } - } - } - } - - this.name = scaleName; - this.notes = []; - this.tonic = tonic; - this.scale = scale; - - for (i = 0, length = scale.length; i < length; i++) { - this.notes.push(teoria.interval(tonic, scale[i])); - } - } - - TeoriaScale.prototype = { - simple: function() { - var sNotes = []; - - for (var i = 0, length = this.notes.length; i < length; i++) { - sNotes.push(this.notes[i].toString(true)); - } - - return sNotes; - }, - - type: function() { - var length = this.notes.length - 2; - if (length < 8) { - return ['di', 'tri', 'tetra', 'penta', 'hexa', 'hepta', 'octa'][length] + - 'tonic'; - } - }, - - get: function(i) { - if (typeof i === 'string' && i in kStepNumber) { - i = parseInt(kStepNumber[i], 10); - } - - return this.notes[i - 1]; - }, - - solfege: function(index, showOctaves) { - var i, length, solfegeArray = []; - - // Return specific index in scale - if (index) { - return this.get(index).solfege(this, showOctaves); - } - - // Return an array of solfege syllables - for (i = 0, length = this.notes.length; i < length; i++) { - solfegeArray.push(this.notes[i].solfege(this, showOctaves)); - } - - return solfegeArray; - }, - - interval: function(interval, direction) { - return new TeoriaScale(this.tonic.interval(interval, direction), - this.scale); - }, - - transpose: function(interval, direction) { - var scale = new TeoriaScale(this.tonic.interval(interval, direction), - this.scale); - this.notes = scale.notes; - this.scale = scale.scale; - this.tonic = scale.tonic; - - return this; - } - }; - - - teoria.scale.scales.ionian = teoria.scale.scales.major = - ['P1', 'M2', 'M3', 'P4', 'P5', 'M6', 'M7']; - teoria.scale.scales.dorian = ['P1', 'M2', 'm3', 'P4', 'P5', 'M6', 'm7']; - teoria.scale.scales.phrygian = ['P1', 'm2', 'm3', 'P4', 'P5', 'm6', 'm7']; - teoria.scale.scales.lydian = ['P1', 'M2', 'M3', 'A4', 'P5', 'M6', 'M7']; - teoria.scale.scales.mixolydian = ['P1', 'M2', 'M3', 'P4', 'P5', 'M6', 'm7']; - teoria.scale.scales.aeolian = teoria.scale.scales.minor = - ['P1', 'M2', 'm3', 'P4', 'P5', 'm6', 'm7']; - teoria.scale.scales.locrian = ['P1', 'm2', 'm3', 'P4', 'd5', 'm6', 'm7']; - teoria.scale.scales.majorpentatonic = ['P1', 'M2', 'M3', 'P5', 'M6']; - teoria.scale.scales.minorpentatonic = ['P1', 'm3', 'P4', 'P5', 'm7']; - teoria.scale.scales.chromatic = teoria.scale.scales.harmonicchromatic = - ['P1', 'm2', 'M2', 'm3', 'M3', 'P4', 'A4', 'P5', 'm6', 'M6', 'm7', 'M7']; - - - teoria.TeoriaNote = TeoriaNote; - teoria.TeoriaChord = TeoriaChord; - teoria.TeoriaScale = TeoriaScale; - teoria.TeoriaInterval = TeoriaInterval; - - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = teoria; - } - exports.teoria = teoria; - } else if (typeof this !== 'undefined') { - this.teoria = teoria; - } else if (typeof window !== 'undefined') { - window.teoria = teoria; - } -})(); - diff --git a/dist/teoria.min.js b/dist/teoria.min.js deleted file mode 100644 index 4647700..0000000 --- a/dist/teoria.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(){"use strict";function e(e,t){return e=s[e],t=s[t],e.distance>t.distance?t.distance+12-e.distance:t.distance-e.distance}function t(e,t,i){for(;i>0;i--)e+=t;return e}function i(e,t){if("string"!=typeof e)return null;t=t||{},this.name=e,this.duration={value:t.value||4,dots:t.dots||0},this.accidental={value:0,sign:""};var i,n,r,a,o=/^([a-h])(x|#|bb|b?)(-?\d*)/i,s=/^([a-h])(x|#|bb|b?)([,\']*)$/i,l=e.match(o);if(l&&e===l[0]&&0!==l[3].length)r=l[1].toLowerCase(),a=parseInt(l[3],10),l[2].length>0&&(i=l[2].toLowerCase(),n=w[l[2]]);else{if(e=e.replace(/\u2032/g,"'").replace(/\u0375/g,","),l=e.match(s),!l||e!==l[0])throw Error("Invalid note format");if(r=l[1],a=l[3],l[2].length>0&&(i=l[2].toLowerCase(),n=w[l[2]]),0===a.length)a=r===r.toLowerCase()?3:2;else if(a.match(/^'+$/)){if(r===r.toUpperCase())throw Error("Format must respect the Helmholtz notation");a=3+a.length}else{if(!a.match(/^,+$/))throw Error("Invalid characters after note name.");if(r===r.toLowerCase())throw Error("Format must respect the Helmholtz notation");a=2-a.length}}this.name=r.toLowerCase(),this.octave=a,i&&(this.accidental.value=n,this.accidental.sign=i)}function n(e,t,i){var n=e>=8&&1===e%7?8*(e%7):(e-1)%7+1,r=Math.ceil((e-n)/8),a=c[n-1];if(!(t in m[a.quality]))throw Error("Invalid interval quality");this.interval=e,this.quality=t,this.direction="down"===i?"down":"up",this.simpleInterval=n,this.simpleIntervalType=a,this.compoundOctaves=r}function r(e,t){function n(e){for(var t=0,i=e.length;i>t;t++)m[t+1]=e[t];f=e.length}if(!(e instanceof i))return null;t=t||"",this.name=e.name.toUpperCase()+e.accidental.sign+t,this.symbol=t,this.root=e,this.intervals=[],this._voicing=[];var r,a,s,l,h,c,d="quality",u=[],m=["P1","M3","P5","m7","M9","P11","M13"],f=2;for(t=t.replace(/[,\s\(\)]/g,""),h=t.split("/"),2===h.length?(t=h[0],h=h[1]):h=null,r=0,a=t.length;a>r&&(s=t[r]);r++){switch(d){case"quality":l=a>=r+3?t.substr(r,3):null,c=l in p?l:s in p?s:"",n(p[c]),r+=c.length-1,d="extension";break;case"extension":if(s="1"===s&&t[r+1]?parseFloat(t.substr(r,2)):parseFloat(s),isNaN(s)||6===s)6===s?(m[3]="M6",f=3>f?3:f):r-=1;else{if(f=(s-1)/2,f!==Math.round(f))throw Error("Invalid interval extension: "+s.toString(10));("o"===c||"dim"===c)&&(m[3]="d7"),r+=(s+"").length-1}d="alterations";break;case"alterations":var v,g=t.substr(r).split(/(#|b|add|maj|sus|M)/),y=!1,w=!1;if(1===g.length)throw Error("Invalid alterations");if(0!==g[0].length)throw Error("Invalid token: '"+g[0]+"'");for(var M=1,b=g.length;b>M;M++)switch(v=g[M+1],g[M]){case"M":case"maj":f=3>f?3:f,"7"===v&&M++,m[3]="M7";break;case"sus":var P="P4";("2"===v||"4"===v)&&(M++,"2"===v&&(P="M2")),m[1]=P;break;case"add":v&&!isNaN(+v)&&("9"===v?u.push("M9"):"11"===v?u.push("P11"):"13"===v&&u.push("M13"),M+=v.length);break;case"b":y=!0;break;case"#":w=!0;break;default:if(0===g[M].length)break;var I,A,q=+g[M];if(isNaN(q)||(q+"").length!==g[M].length)throw Error("Invalid token: '"+g[M]+"'");if(6===q){m[3]=w?"A6":y?"m6":"M6",f=3>f?3:f;continue}if(A=(q-1)/2,A>f&&(f=A),5>q||7===q||A!==Math.round(A))throw Error("Invalid interval alteration: "+q);I=m[A][0],w?"d"===I?I="m":"m"===I?I="M":("M"===I||"P"===I)&&(I="A"):y&&("A"===I?I="M":"M"===I?I="m":("m"===I||"P"===I)&&(I="d")),w=y=!1,m[A]=I+q}d="ended"}if("ended"===d)break}for(this.intervals=m.slice(0,f+1).concat(u).map(function(e){return o.interval(e)}),r=0,a=this.intervals.length;a>r;r++)this._voicing[r]=this.intervals[r];if(h){var x,k,T=this.intervals,C=0;for(k=o.note(h+(e.octave+1)),x=o.interval.between(e,k),h=x.simpleInterval,"up"===x.direction&&(x=x.invert(),x.direction="down"),this._voicing=[x],r=0;a>r;r++)T[r].interval!==h&&(C++,this._voicing[C]=T[r])}}function a(e,t){var n,r,a;if(!(e instanceof i))throw Error("Invalid Tonic");if("string"==typeof t){if(n=t,t=o.scale.scales[t],!t)throw Error("Invalid Scale")}else for(r in o.scale.scales)if(o.scale.scales.hasOwnProperty(r)&&""+o.scale.scales[r]==""+t){n=r;break}for(this.name=n,this.notes=[],this.tonic=e,this.scale=t,r=0,a=t.length;a>r;r++)this.notes.push(o.interval(e,t[r]))}var o={},s={c:{name:"c",distance:0,index:0},d:{name:"d",distance:2,index:1},e:{name:"e",distance:4,index:2},f:{name:"f",distance:5,index:3},g:{name:"g",distance:7,index:4},a:{name:"a",distance:9,index:5},b:{name:"b",distance:11,index:6},h:{name:"h",distance:11,index:6}},l=["c","d","e","f","g","a","b"],h={.25:"longa",.5:"breve",1:"whole",2:"half",4:"quarter",8:"eighth",16:"sixteenth",32:"thirty-second",64:"sixty-fourth",128:"hundred-twenty-eighth"},c=[{name:"first",quality:"perfect",size:0},{name:"second",quality:"minor",size:1},{name:"third",quality:"minor",size:3},{name:"fourth",quality:"perfect",size:5},{name:"fifth",quality:"perfect",size:7},{name:"sixth",quality:"minor",size:8},{name:"seventh",quality:"minor",size:10},{name:"octave",quality:"perfect",size:12}],d={P:"perfect",M:"major",m:"minor","-":"minor",A:"augmented","+":"augmented",AA:"doubly augmented",d:"diminished",dd:"doubly diminished",min:"minor",aug:"augmented",dim:"diminished"},u={perfect:"P",major:"M",minor:"m",augmented:"A","doubly augmented":"AA",diminished:"d","doubly diminished":"dd"},m={perfect:{"doubly diminished":-2,diminished:-1,perfect:0,augmented:1,"doubly augmented":2},minor:{"doubly diminished":-2,diminished:-1,minor:0,major:1,augmented:2,"doubly augmented":3}},f={perfect:"perfect",major:"minor",minor:"major",augmented:"diminished","doubly augmented":"doubly diminished",diminished:"augmented","doubly diminished":"doubly augmented"},v={perfect:["doubly diminished","diminished","perfect","augmented","doubly augmented"],minor:["doubly diminished","diminished","minor","major","augmented","doubly augmented"]},p={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"]},g={major:"M",minor:"m",augmented:"aug",diminished:"dim","half-diminished":"7b5",power:"5",dominant:"7"},y={"-2":"bb","-1":"b",0:"",1:"#",2:"x"},w={bb:-2,b:-1,"#":1,x:2},M={first:"1",tonic:"1",second:"2",third:"3",fourth:"4",fifth:"5",sixth:"6",seventh:"7",ninth:"9",eleventh:"11",thirteenth:"13"},b={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"};o.note=function(e,t){return new i(e,t)},o.note.fromKey=function(e){var t=Math.floor((e-4)/12),i=e-12*t-4,n=s[l[Math.round(i/2)]],r=n.name;return i>n.distance?r+="#":n.distance>i&&(r+="b"),o.note(r+(t+1))},o.note.fromFrequency=function(e,t){var i,n,r;return t=t||440,i=49+12*((Math.log(e)-Math.log(t))/Math.log(2)),i=Math.round(i),r=t*Math.pow(2,(i-49)/12),n=1200*(Math.log(e/r)/Math.log(2)),{note:o.note.fromKey(i),cents:n}},o.note.fromMIDI=function(e){return o.note.fromKey(e-20)},o.chord=function(e,t){if("string"==typeof e){var n,a;if(n=e.match(/^([a-h])(x|#|bb|b?)/i),n&&n[0])return a="number"==typeof t?t.toString(10):"4",new r(o.note(n[0].toLowerCase()+a),e.substr(n[0].length))}else if(e instanceof i)return new r(e,t||"");throw Error("Invalid Chord. Couldn't find note name")},o.interval=function(e,t,r){var a,s,l,h;if("string"==typeof e){if(h=e.match(/^(AA|A|P|M|m|d|dd)(-?\d+)$/),!h)throw Error("Invalid string-interval format");return a=d[h[1]],s=parseInt(h[2],10),r="down"===t||0>s?"down":"up",new n(Math.abs(s),a,r)}if("string"==typeof t&&e instanceof i)return l=o.interval(t,r),o.interval.from(e,l);if(t instanceof i&&e instanceof i)return o.interval.between(e,t);throw Error("Invalid parameters")},o.interval.from=function(t,i){var n,r,a,h,c,d,u;return u="down"===i.direction?-1:1,d=i.simpleInterval-1,d=u*d,h=s[t.name].index+d,h>l.length-1?h-=l.length:0>h&&(h+=l.length),n=l[h],c=e(t.name,n),r=u>0?i.simpleIntervalType.size+i.qualityValue()-c:e(n,t.name)-(i.simpleIntervalType.size+i.qualityValue()),r+=t.accidental.value,a=Math.floor((t.key()-t.accidental.value+c-4)/12),a+=1+u*i.compoundOctaves,r>=10?r-=12:-10>=r&&(r+=12),8===i.simpleInterval?a+=u:0>u&&a--,n+=y[r],o.note(n+a.toString(10))},o.interval.between=function(e,t){var i,r,a,o,s,l="up",h=1;return i=t.key()-e.key(),a=t.key(!0)-e.key(!0),0>a&&(a=-a,l="down",h=-1),r=c[a%7],s=v[r.quality],o=s[(h*i-r.size+2)%12],new n(a+1,o,l)},o.interval.invert=function(e){return""+o.interval(e).invert()},o.scale=function(e,t){return e instanceof i||(e=o.note(e)),new a(e,t)},o.scale.scales={},i.prototype={key:function(e){var t;return e?(t=Math.ceil(s[this.name].distance/2),7*(this.octave-1)+3+t):(t=s[this.name].distance+this.accidental.value,12*(this.octave-1)+4+t)},fq:function(e){return e=e||440,e*Math.pow(2,(this.key()-49)/12)},chroma:function(){var e=(s[this.name].distance+this.accidental.value)%12;return 0>e?e+12:e},scale:function(e){return o.scale(this,e)},interval:function(e,t){return o.interval(this,e,t)},transpose:function(e,t){var i=o.interval(this,e,t);return this.name=i.name,this.octave=i.octave,this.accidental=i.accidental,this},chord:function(e){return e=e in g?g[e]:e,new r(this,e)},helmholtz:function(){var e=3>this.octave?this.name.toUpperCase():this.name.toLowerCase(),i=3>this.octave?",":"'",n=2>this.octave?2-this.octave:this.octave-3;return t(e+this.accidental.sign,i,n)},scientific:function(){return this.name.toUpperCase()+this.accidental.sign+this.octave},enharmonics:function(){var e=[],t=this.key(),i=this.interval("m2","up"),n=this.interval("m2","down"),r=i.key()-i.accidental.value,a=n.key()-n.accidental.value,o=t-r;return 3>o&&o>-3&&(i.accidental={value:o,sign:y[o]},e.push(i)),o=t-a,3>o&&o>-3&&(n.accidental={value:o,sign:y[o]},e.push(n)),e},solfege:function(e,i){if(!(e instanceof a))throw Error("Invalid Scale");var n,r,o,s=e.tonic.interval(this);return"down"===s.direction&&(s=s.invert()),i&&(o=(this.key(!0)-e.tonic.key(!0))/7,o=o>=0?Math.floor(o):-Math.ceil(-o),r=o>=0?"'":","),n=b[s.simple(!0)],i?t(n,r,Math.abs(o)):n},durationName:function(){return h[this.duration.value]},durationInSeconds:function(e,t){var i=60/e/(this.duration.value/4)/(t/4);return 2*i-i/Math.pow(2,this.duration.dots)},scaleDegree:function(e){var t=e.tonic.interval(this);return t="down"===t.direction||8===t.simpleInterval?t.invert():t,e.scale.indexOf(t.simple(!0))+1},toString:function(e){var t=e?"":this.octave;return this.name.toLowerCase()+this.accidental.sign+t}},n.prototype={semitones:function(){return this.simpleIntervalType.size+this.qualityValue()+12*this.compoundOctaves},simple:function(e){var t=this.simpleInterval;return t="down"!==this.direction||e?t:-t,u[this.quality]+(""+t)},compound:function(e){var t=this.simpleInterval+7*this.compoundOctaves;return t="down"!==this.direction||e?t:-t,u[this.quality]+(""+t)},isCompound:function(){return this.compoundOctaves>0},invert:function(){var e=this.simpleInterval;return e=9-e,new n(e,f[this.quality],this.direction)},qualityValue:function(){var e=this.simpleIntervalType.quality,t=this.quality;return m[e][t]},equal:function(e){return this.interval===e.interval&&this.quality===e.quality},greater:function(e){var t=this.semitones(),i=e.semitones();return t===i?this.interval>e.interval:t>i},smaller:function(e){return!this.equal(e)&&!this.greater(e)},toString:function(){return this.compound()}},r.prototype={notes:function(){for(var e=this.voicing(),t=[],i=0,n=e.length;n>i;i++)t.push(o.interval.from(this.root,e[i]));return t},voicing:function(e){if(!e)return this._voicing;this._voicing=[];for(var t=0,i=e.length;i>t;t++)this._voicing[t]=o.interval(e[t]);return this},resetVoicing:function(){this._voicing=this.intervals},dominant:function(e){return e=e||"",new r(this.root.interval("P5"),e)},subdominant:function(e){return e=e||"",new r(this.root.interval("P4"),e)},parallel:function(e){e=e||"";var t=this.quality();if("triad"!==this.chordType()||"diminished"===t||"augmented"===t)throw Error("Only major/minor triads have parallel chords");return"major"===t?new r(this.root.interval("m3","down"),"m"):new r(this.root.interval("m3","up"))},quality:function(){for(var e,t,i,n=this.intervals,r=0,a=n.length;a>r;r++)3===n[r].interval?e=n[r]:5===n[r].interval?t=n[r]:7===n[r].interval&&(i=n[r]);return e?(e="down"===e.direction?e.invert():e,e=e.simple(),t&&(t="down"===t.direction?t.invert():t,t=t.simple()),i&&(i="down"===i.direction?i.invert():i,i=i.simple()),"M3"===e?"A5"===t?"augmented":"P5"===t?"m7"===i?"dominant":"major":"major":"m3"===e?"P5"===t?"minor":"d5"===t?"m7"===i?"half-diminished":"diminished":"minor":void 0):void 0},chordType:function(){var e,t,i,n,r,a=this.intervals.length;if(2===a)return"dyad";if(3===a){for(t={first:!1,third:!1,fifth:!1},n=0;a>n;n++)e=this.intervals[n],i=e.invert(),e.simpleIntervalType.name in t?t[e.simpleIntervalType.name]=!0:i.simpleIntervalType.name in t&&(t[i.simpleIntervalType.name]=!0);r=t.first&&t.third&&t.fifth?"triad":"trichord"}else if(4===a){for(t={first:!1,third:!1,fifth:!1,seventh:!1},n=0;a>n;n++)e=this.intervals[n],i=e.invert(),e.simpleIntervalType.name in t?t[e.simpleIntervalType.name]=!0:i.simpleIntervalType.name in t&&(t[i.simpleIntervalType.name]=!0);t.first&&t.third&&t.fifth&&t.seventh&&(r="tetrad")}return r||"unknown"},get:function(e){if("string"==typeof e&&e in M){var t,i,n=this.intervals;for(e=M[e],t=0,i=n.length;i>t;t++)if(n[t].interval===+e)return o.interval.from(this.root,n[t]);return null}throw Error("Invalid interval name")},interval:function(e,t){return new r(this.root.interval(e,t),this.symbol)},transpose:function(e,t){return this.root.transpose(e,t),this.name=this.root.name.toUpperCase()+this.root.accidental.sign+this.symbol,this},toString:function(){return this.name}},a.prototype={simple:function(){for(var e=[],t=0,i=this.notes.length;i>t;t++)e.push(this.notes[t].toString(!0));return e},type:function(){var e=this.notes.length-2;return 8>e?["di","tri","tetra","penta","hexa","hepta","octa"][e]+"tonic":void 0},get:function(e){return"string"==typeof e&&e in M&&(e=parseInt(M[e],10)),this.notes[e-1]},solfege:function(e,t){var i,n,r=[];if(e)return this.get(e).solfege(this,t);for(i=0,n=this.notes.length;n>i;i++)r.push(this.notes[i].solfege(this,t));return r},interval:function(e,t){return new a(this.tonic.interval(e,t),this.scale)},transpose:function(e,t){var i=new a(this.tonic.interval(e,t),this.scale);return this.notes=i.notes,this.scale=i.scale,this.tonic=i.tonic,this}},o.scale.scales.ionian=o.scale.scales.major=["P1","M2","M3","P4","P5","M6","M7"],o.scale.scales.dorian=["P1","M2","m3","P4","P5","M6","m7"],o.scale.scales.phrygian=["P1","m2","m3","P4","P5","m6","m7"],o.scale.scales.lydian=["P1","M2","M3","A4","P5","M6","M7"],o.scale.scales.mixolydian=["P1","M2","M3","P4","P5","M6","m7"],o.scale.scales.aeolian=o.scale.scales.minor=["P1","M2","m3","P4","P5","m6","m7"],o.scale.scales.locrian=["P1","m2","m3","P4","d5","m6","m7"],o.scale.scales.majorpentatonic=["P1","M2","M3","P5","M6"],o.scale.scales.minorpentatonic=["P1","m3","P4","P5","m7"],o.scale.scales.chromatic=o.scale.scales.harmonicchromatic=["P1","m2","M2","m3","M3","P4","A4","P5","m6","M6","m7","M7"],o.TeoriaNote=i,o.TeoriaChord=r,o.TeoriaScale=a,o.TeoriaInterval=n,"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=o),exports.teoria=o):this!==void 0?this.teoria=o:"undefined"!=typeof window&&(window.teoria=o)})(); \ No newline at end of file