A collection of functions to manipulate musical notes
ES6:
import { Note } from "@tonaljs/tonal";
nodejs:
const { Note } = require("@tonaljs/tonal");
Given a note name, it returns an object with the following properties:
- name: the note name
- pc: the pitch class name
- letter: the note letter
- step: the letter number (0..6)
- acc: the note accidentals
- alt: the accidental number (..., -1 = 'b', 0 = '', 1 = '#', ...)
- oct: the octave (or null if not present)
- chroma: the note chroma (0..11)
- midi: the note midi or null if octave is not present
- freq: the note frequency in Hertzes, or null if the octave is note present
Note.get("C4"); // => { name: "C4", midi: 60, ... }
It has several shorthands to retrieve properties easily:
Note.name("fx4"); // => "F##4"
Note.pitchClass("Ab5"); // => "Ab"
Note.accidentals("Eb"); // => 'Eb'
Note.octave("C4"); // => 4
Note.midi("A4"); // => 69
Note.freq("A4"); // => 440
Note.chroma("D"); // => 2
["C", "D", "E"].map(Note.chroma); // => [0, 2, 4]
Given a midi number, returns the note name. This function is the same as midiToNoteName
from @tonaljs/midi
Note.fromMidi(61); // => "Db4"
Note.fromMidi(61.7); // => "D4"
[60, 61, 62].map(Note.fromMidi); // => ["C4", "Db4", "D4"]
There's also a Note.fromMidiSharps
version:
Note.fromMidiSharps(61); // => "C#4"
Given a frequency in Hz, returns the note name.
Note.fromFreq(440); // => "A4"
It rounds to the nearest name:
[440, 550, 660].map(t.Note.fromFreq); // => [ 'A4', 'Db5', 'E5' ]
There's also a Note.fromFreqSharps
version:
[440, 550, 660].map(t.Note.fromFreqSharps); // => [ 'A4', 'C#5', 'E5' ]
Transpose a note by an interval. It returns the note name or "" if not valid parameters.
Examples:
Note.transpose("d3", "3M"); // => "F#3"
Note.transpose("D", "3M"); // => "F#"
transposeBy
and transposeFrom
are currified versions of this function to make easy work with arrays:
["C", "D", "E"].map(Note.transposeBy("5P"));
// => ["G", "A", "B"]
["1P", "3M", "5P"].map(Note.transposeFrom("C"));
// => ["C", "E", "G"]
Transpose a note a given number of fifths:
Note.transposeFifths("G4", 3); // => "E6"
Note.transposeFifths("G", 3); // => "E"
[0, 1, 2, 3, 4, 5, 6].map((n) => transposeFifths("F#", n));
// => ["F#", "C#", "G#", "D#", "A#", "E#", "B#"]
[0, -1, -2, -3, -4, -5, -6].map((n) => transposeFifths("Bb", n));
// => ["Bb", "Eb", "Ab", "Db", "Gb", "Cb", "Fb"]
Find the interval between two notes:
Note.distance("C", "D").toEqual("2M");
Note.distance("C3", "E3").toEqual("3M");
Note.distance("C3", "E4").toEqual("10M");
Get note names of an array of anything. Notice that names are normalized:
Note.names(["fx", "bb", 12, "nothing", {}, null])) // => ["F##", "Bb"];
Without parameters, it returns a list of natural pitch classes:
Note.names(); // =>["C", "D", "E", "F", "G", "A", "B"]
Sort an array of note names in ascending order. Pitch classes are listed before notes. Anything that is not a note is removed:
Note.sortedNames(["c2", "c5", "c1", "c0", "c6", "c"]);
// => ['C', 'C0', 'C1', 'C2', 'C5', 'C6']
Note.sortedNames(["c", "F", "G", "a", "b", "h", "J"]);
// => ['C', 'F', 'G', 'A', 'B']
An optional comparator can be passed as a second argument:
Note.sortedNames(["c2", "c5", "c1", "c0", "c6", "c"], Note.descending);
// => ['C6', 'C5', 'C2', 'C3', 'C1', 'C0']
Sort notes ascending and remove duplicates.
Given a note name, return the same note with less accidentals (or "" if not a valid note):
Note.simplify("C#"); // => "C#"
Note.simplify("C##"); // => "D"
Note.simplify("C###"); // => "D#"
Given a note name, returns its enharmonic (or "" if not valid note):
Note.enharmonic("C#"); // => "Db"
Note.enharmonic("C##"); // => "D"
Note.enharmonic("C###"); // => "Eb"
The destination pitch class can be enforced to calculate the octave:
Note.enharmonic("F2", "E#"); // => "E#2"
Note.enharmonic("B2", "Cb"); // => "Cb3"
Note.enharmonic("C2", "B#"); // => "B#1"
Enforced pitch class must have the same chroma as the note, otherwise "" is returned:
Note.enharmonic("F2", "Eb"); // => ""