Giter Site home page Giter Site logo

etude.js's Introduction

etude.js

npm

JavaScript Music Theory API

Try it here!

A port of etude, the Java version. While similar, there are a few changes to take note of:

  • asList was removed due to the way arrays are implemented in JavaScript (JavaScript arrays can do most of what Java ArrayLists can do).

  • Streams was ported for use with Letter and Scale. Contains filter, map, limit, and skip.

  • Lack of most enum members. values, ordinal, and valueOf were ported (values was also "overloaded" via default parameters to take in startingElement where appropriate).

  • Pitch not being Comparable. However, compareTo was ported.

  • Complete alteration of utility methods. These were dependent on what was available in each respective language.

  • Lack of type checks due to the differences between Java and JavaScript as languages. However, static type checks are available if using TypeScript.

  • Any whole number will not contain a decimal point when converted to a string (e.g. 1.0 will be converted to "1.0" in Java whereas 1.0 will be converted to "1" in JavaScript). This is relevant for Value.DOUBLE_WHOLE and Value.WHOLE.

  • Small syntactical changes

    Java JavaScript Reason
    EnumName.values().length EnumName.size To avoid cloning values array
    interval.getNumber() interval.distance number is a reserved word in JavaScript
    policy.test(key) policy(key) To allow let policy = k => {...} assignment

Installation

Browser

Add this line to your html file:

<script type="text/javascript" src="https://unpkg.com/etude/js/etude-browser.js"></script>

The src pulls from the latest version of etude on npm. This may cause builds to break if a backward-incompatible version is released. To target a specific version, include the version number in the src:

<script type="text/javascript" src="https://unpkg.com/etude@version/js/etude-browser.js"></script>

More information on the version tag can be found at unpkg.

If you do not wish to use unpkg, use Browserify along with the require methods below. If you do not wish to use either, download the file and add this line to your html file:

<script type="text/javascript" src="path/to/file/etude-browser.js"></script>

Any of the above methods adds etude to the global namespace. To avoid prepending module package names to each module name with each use (e.g. etude.theory.Letter), add these lines:

const {error, theory, util} = etude;
const {EtudeError} = error;
const {Accidental, Chord, Degree, Direction, Dynamic, Interval, Inversion, Key, KeySignature, Letter, Mode, MusicConstants, Note, Pitch, Policy, Scale, Tempo, TimeSignature, Value} = theory;
const {CircularIterator, CircularStream, ImmutablePrioritySet, InfiniteIterator, InfiniteStream} = util;

require

First install the package.

npm install etude

Then include the package in your code using one of the following methods:

Top level module:

const etude = require("etude");

This method requires you to prepend module package names to each module name with each use (e.g. etude.theory.Letter).

Each module separately:

const {error, theory, util} = require("etude");
const {EtudeError} = error;
const {Accidental, Chord, Degree, Direction, Dynamic, Interval, Inversion, Key, KeySignature, Letter, Mode, MusicConstants, Note, Pitch, Policy, Scale, Tempo, TimeSignature, Value} = theory;
const {CircularIterator, CircularStream, ImmutablePrioritySet, InfiniteIterator, InfiniteStream} = util;

Examples

For extensive example usage, refer to the Java version's unit tests.

Accidental

let accidental = Accidental.FLAT;
console.log(accidental.toString()); // b
console.log(accidental.getOffset()); // -1

accidental = Accidental.DOUBLE_SHARP;
console.log(accidental.toString()); // x
console.log(accidental.getOffset()); // 2

accidental = Accidental.fromOffset(-3);
console.log(accidental.toString()); // bbb
console.log(accidental === Accidental.TRIPLE_FLAT); // true

accidental = Accidental.fromString("n");
console.log(accidental.getOffset()); // 0
console.log(accidental === Accidental.NATURAL); // true

Chord

let chord = new Chord(Pitch.fromString("C4"), Chord.Quality.MAJOR);
console.log(chord.toString()); // [Cn4(48), En4(52), Gn4(55)]

chord = Chord
  .builder()
  .setRoot(Pitch.fromString("Ab4"))
  .add(Chord.Quality.MINOR)
  .add(Interval.fromString("M6"))
  .build();
console.log(chord.toString()); // [Ab4(56), Cb5(59), Eb5(63), Fn5(65)]

chord = Chord
  .builder()
  .setRoot(Pitch.fromString("C4"))
  .add(Chord.Quality.DIMINISHED_SEVENTH)
  .setInversion(Inversion.FIRST)
  .build();
console.log(chord.toString()); // [Eb4(51), Gb4(54), Bbb4(57), Cn5(60)]

Degree

let degree = Degree.TONIC;
console.log(degree.getValue()); // 1

degree = Degree.fromValue(5);
console.log(degree.toString()); // DOMINANT

Direction

let direction = Direction.ASCENDING;
console.log(direction === Direction.DEFAULT); // true

direction = Direction.DESCENDING;
console.log(direction !== Direction.DEFAULT); // true

Dynamic

let dynamic = Dynamic.PIANO;
console.log(dynamic.toString()); // p
console.log(dynamic.crescendo().toString()); // mp
console.log(dynamic.diminuendo().toString()); // pp

dynamic = Dynamic.fromString("mf");
console.log(dynamic === Dynamic.MEZZO_FORTE); // true
console.log(dynamic.crescendo() === Dynamic.FORTE); // true

Interval

let interval = new Interval(Interval.Quality.MAJOR, 6);
console.log(interval.getOffset()); // 9

interval = Interval.between(Pitch.fromString("Eb4"), Pitch.fromString("Ab4"));
console.log(interval.toString()); // P4

Inversion

let inversion = Inversion.ROOT;
console.log(inversion.getValue()); // 0

inversion = Inversion.THIRD;
console.log(inversion.getValue()); // 3 

Key

let key = new Key(Letter.C);
console.log(key.toString()); // C

key = new Key(Letter.G, Accidental.SHARP);
console.log(key.toString()); // G#

console.log(key.step(1).toString()); // A
console.log(key.step(2).toString()); // A#

key = new Key(Letter.F);
let ks = new KeySignature(Key.fromString("G"), KeySignature.Quality.MAJOR);
console.log(key.apply(ks).toString()); // F#

key = new Key(Letter.C, Accidental.FLAT);
console.log(key.sharp().toString()); // C#
console.log(key.none().toString()); // C
console.log(key.doubleFlat().toString()); // Cbb
console.log(key.isFlat()); // true

let anotherKey = key.getEnharmonicEquivalent(Letter.A);
console.log(anotherKey.toString()); // Ax
console.log(Key.isEnharmonic(key, anotherKey)); // true

key = Key.fromString("Eb");
console.log(key.getLetter() === Letter.E); // true
console.log(key.getAccidental() === Accidental.FLAT); // true

KeySignature

let ks = new KeySignature(Key.fromString("D"), KeySignature.Quality.MAJOR);

console.log(ks.keyOf(Degree.MEDIANT).toString()); // F#
console.log(ks.degreeOf(Key.fromString("G")).toString()); // SUBDOMINANT

console.log(ks.getKeysWithAccidentals().toString()); // F#,C#

let parallel = ks.getParallel();
console.log(parallel.getKey().toString()); // D
console.log(parallel.getQuality().toString()); // MINOR

let relative = ks.getRelative();
console.log(relative.getKey().toString()); // B
console.log(relative.getQuality().toString()); // MINOR

console.log(KeySignature.ORDER_OF_SHARPS.toString()); // F,C,G,D,A,E,B

Letter

let letter = Letter.A;
console.log(letter.getOffset()); // 9

letter = Letter.fromChar('c');
console.log(letter === Letter.C); // true

let letters = Letter
  .stream(Letter.E)
  .limit(10);
console.log(letters.toString()); // E,F,G,A,B,C,D,E,F,G

letters = Letter
  .stream(Direction.DESCENDING, Letter.C)
  .limit(8);
console.log(letters.toString());  // C,B,A,G,F,E,D,C

Mode

let mode = Mode.IONIAN;
console.log(mode.getStepPattern().toString()); // 2,2,1,2,2,2,1

MusicConstants

console.log(MusicConstants.KEYS_IN_OCTAVE); // 12
console.log(MusicConstants.SMALLEST_PROGRAM_NUMBER); // 0
console.log(MusicConstants.LARGEST_PROGRAM_NUMBER); // 127

Note

let note = new Note(Pitch.fromString("C4"), Value.QUARTER);
console.log(note.toString()); // C4(48)[QUARTER]

note = Note.fromString("Db5[1]");
console.log(note.getPitch().toString()); // Db5(61)
console.log(note.getValue().toString()); // WHOLE

Pitch

let pitch = new Pitch(Key.fromString("Bbb"), 4);
console.log(pitch.toString()); // Bbb4(57)

let ks = new KeySignature(Key.fromString("F"), KeySignature.Quality.MAJOR);
pitch = pitch.apply(ks);
console.log(pitch.toString()); // Bb4(58)

console.log(pitch.step(3).toString()); // C#5(61)
console.log(pitch.step(3, Policy.prioritize(Policy.FLAT)).toString()); // Db5(61)

let interval = new Interval(Interval.Quality.PERFECT, 4);
console.log(pitch.step(interval).toString()); // Eb5(63)

pitch = pitch.getHigherPitch(Key.fromString("C"));
console.log(pitch.toString()); // C5(60)

console.log(Pitch.isEnharmonic(Pitch.fromString("F#4"), Pitch.fromString("Gb4"))); // true

pitch = Pitch.fromProgramNumber(48);
console.log(pitch.toString()); // C4(48)

pitch = Pitch.fromString("Ax7");
console.log(pitch.getKey().equals(Key.fromString("Ax"))); // true
console.log(pitch.getOctave() === 7); // true

Policy

let policy = Policy.DOUBLE_FLAT;
console.log(policy(Key.fromString("C#"))); // false
console.log(policy(Key.fromString("Ebb"))); // true

policy = Policy.SHARPS;
console.log(policy(Key.fromString("C#"))); // true
console.log(policy(Key.fromString("C#x"))); // true

policy = Policy.matchLetter(Letter.E);
console.log(policy(Key.fromString("Dn"))); // false
console.log(policy(Key.fromString("Ebb"))); // true

let ks = new KeySignature(Key.fromString("A"), KeySignature.Quality.MAJOR);
policy = Policy.matchKeySignature(ks);
console.log(policy(Key.fromString("F"))); // false
console.log(policy(Key.fromString("F#"))); // true

let key = Key.fromString("G");
let policies = Policy.prioritize(Policy.TRIPLE_SHARP, Policy.TRIPLE_FLAT, Policy.NONE_OR_NATURAL);
console.log(key.step(2, policies).toString()); // Cbbb

Scale

let scale = new Scale(Key.fromString("Ab"), Scale.Quality.MAJOR);
let keys = scale
  .stream()
  .limit(8);
console.log(keys.toString()); // Ab,Bb,C,Db,Eb,F,G,Ab

keys = scale
  .stream(Direction.DESCENDING)
  .limit(8);
console.log(keys.toString()); // Ab,G,F,Eb,Db,C,Bb,Ab

scale = new Scale(Key.fromString("G"), Scale.Quality.HARMONIC_MINOR);
keys = scale
  .stream()
  .limit(8);
console.log(keys.toString()); // G,A,Bb,C,D,Eb,F#,G

keys = scale
  .stream(Policy.prioritize(Policy.TRIPLE_FLAT, Policy.DOUBLE_FLAT))
  .limit(8);
/**
 * NOTE: the first key is G despite the policy prioritizing TRIPLE_FLAT and DOUBLE_FLAT
 * this is because the scale was constructed with G being the initial key
 */
console.log(keys.toString()); // G,Cbbb,Cbb,Dbb,Fbbb,Fbb,Abbb,Abb

// apply the policy on the initial key
scale = new Scale(Key.fromString("G").getEnharmonicEquivalent(Policy.prioritize(Policy.TRIPLE_FLAT, Policy.DOUBLE_FLAT)), Scale.Quality.HARMONIC_MINOR);
keys = scale
  .stream(Policy.prioritize(Policy.TRIPLE_FLAT, Policy.DOUBLE_FLAT))
  .limit(8);
/**
 * NOTE: this begins with Abb
 */
console.log(keys.toString()); // Abb,Cbbb,Cbb,Dbb,Fbbb,Fbb,Abbb,Abb

Tempo

let tempo = Tempo.ANDANTE;
console.log(tempo.getBPM()); // 92
console.log(tempo.getBeatValue() === Value.QUARTER); // true
console.log(tempo.getTempoMarking()); // Andante

tempo = Tempo.PRESTO;
console.log(tempo.getBPM()); // 184
console.log(tempo.getBeatValue() === Value.QUARTER); // true
console.log(tempo.getTempoMarking()); // Presto

tempo = new Tempo(100, Value.HALF);
console.log(tempo.getBPM()); // 100
console.log(tempo.getBeatValue() === Value.HALF); // true
console.log(tempo.getTempoMarking()); // HALF = 100

tempo = new Tempo(150, Value.EIGHTH, "Pretty fast");
console.log(tempo.getBPM()); // 150
console.log(tempo.getBeatValue() === Value.EIGHTH); // true
console.log(tempo.getTempoMarking()); // Pretty fast

TimeSignature

let ts = TimeSignature.COMMON_TIME;
console.log(ts.getDurationOfMeasure()); // 1
console.log(ts.getBeatsPerMeasure()); // 4
console.log(ts.getOneBeat() === Value.QUARTER); // true

ts = new TimeSignature(6, 8);
console.log(ts.getDurationOfMeasure()); // 0.75
console.log(ts.getBeatsPerMeasure()); // 6
console.log(ts.getOneBeat() === Value.EIGHTH); // true

ts = new TimeSignature(3, Value.QUARTER);
console.log(ts.getDurationOfMeasure()); // 0.75
console.log(ts.getBeatsPerMeasure()); // 3
console.log(ts.getOneBeat() === Value.QUARTER); // true

Value

let value = Value.QUARTER;
console.log(value.toString()); // QUARTER
console.log(value.getDuration()); // 0.25

value = Value.fromString("0.25");
console.log(value === Value.QUARTER); // true

value = Value.fromString("QUARTER");
console.log(value === Value.QUARTER); // true

value = Value.fromString("1/4");
console.log(value === Value.QUARTER); // true

value = Value.fromDuration(0.25);
console.log(value === Value.QUARTER); // true

etude.js's People

Contributors

andrewthehan avatar npmcdn-to-unpkg-bot avatar

Stargazers

Jonathan avatar

Watchers

James Cloos avatar  avatar

etude.js's Issues

Use package engines to tell tonic to use node v6

If you set your engines field in the package.json to { node: ">=6" } then Tonic will automatically select 6 as the default node version (and you won't have to tell people to set it themselves).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.