npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@tonaljs/note

v4.11.0

Published

Parse and manipulate music notes in scientific notation

Downloads

10,308

Readme

@tonaljs/note tonal npm version

A collection of functions to manipulate musical notes

Usage

ES6:

import { Note } from "tonal";

nodejs:

const { Note } = require("tonal");

single module:

import { get } from "@tonaljs/note";

API

Note properties

Note.get(noteName: string) => Note

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 not 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"); // => 'b'
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]

Note.fromMidi(midi: number) => string

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"

Note.fromFreq(freq: number) => string

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' ]

Transposition and distances

transpose(note: string, interval: string) => string

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"]

transposeFifths(noteName: string, fifths: number) => string

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"]

Note.distance(from: string, to: string) => string

Find the interval between two notes:

Note.distance("C", "D").toEqual("2M");
Note.distance("C3", "E3").toEqual("3M");
Note.distance("C3", "E4").toEqual("10M");

Named collections

names(array?: any[]) => string[]

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"]

You may be in a situation where you have note names with octaves, but don't want them, remove them like this:

Note.names(["C2", "C#3", "Db4", 12, "nothing", {}, null]).map(Note.pitchClass); // => ['C', 'C#', 'Db']

sortedNames(array?: any[], comparator?: NoteComparator) => string[]

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']

sortedUniqNames(array?: any[]) => string[]

Sort notes ascending and remove duplicates.

Enharmonics

simplify(noteName: string) => string

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#"

enharmonic(noteName: string, pitchClass?: string) => string

Given a note name, returns its enharmonic (or "" if not valid note):

Note.enharmonic("C#"); // => "Db"
Note.enharmonic("C##"); // => "D"
Note.enharmonic("C###"); // => "Eb"

Note.eharmoinic("C##b"); // => ""

Using eharmonic on a natural will return the same value passed in:

Note.eharmonic("C"); // => "C"
Note.eharmonic("C4"); // => "C4"

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"); // => ""