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

twelve-tones

v0.5.0

Published

JavaScript (TypeScript) utilities for working with musical pitches and durations in the 12 tone system.

Downloads

8

Readme

Twelve Tones

JavaScript (TypeScript) utilities for working with musical pitches and durations in the 12 tone system.

Pitches

Creating a Pitch object

import { pitch } from "twelve-tones";

const bFlat = pitch("B", "♭", 4);

Learning more about a Pitch

import { pitch, pitchName } from "twelve-tones";

const bFlat = pitch("B", "♭", 4);
pitchName(bFlat); // => 'B♭4'

// or:
`I like ${bFlat}.`; // => 'I like B♭4.'
import { pitch, midiNoteNumber } from "twelve-tones";

const bFlat = pitch("B", "♭", 4);
midiNoteNumber(bFlat); // => 70
import {
  pitch,
  isSamePitch,
  isEnharmonicEquivalent,
  numberOfAccidentals,
} from "twelve-tones";

const bFlat = pitch("B", "♭", 4);
const aSharp = pitch("A", "♯", 4);

isSamePitch(bFlat, aSharp); // => false

isEnharmonicEquivalent(bFlat, aSharp); // => true

numberOfAccidentals(bFlat); // => -1
numberOfAccidentals(aSharp); // => 1

Transform a Pitch

import { natural, transpose, interval } from "twelve-tones";

const bNatural = natural(bFlat);
numberOfAccidentals(bNatural); // => 0

`I like ${bNatural}.`; // => 'I like B4.'

const eFlat = transpose(bFlat, interval("perfect", "fourth")); // see 'Intervals'

Shorthand notation

Allows for compact, inline creation of pitches and intervals.

import { numberOfAccidentals, natural, transpose } from "twelve-tones";

numberOfAccidentals(["F", "♯♯", 5]); // => 2

natural(["A", "♭♭", 3]); // => Pitch (A3)

const eFlat = transpose(["C", "♮", 4], ["minor", "third"]); // see 'Intervals'
eFlat.toString(); // => E♭4

Intervals

Creating an Interval object

import { interval } from "twelve-tones";

// full notation
const majorThird = interval("major", "third");
const perfectFifth = interval("perfect", "fifth");
const diminishedSeventh = interval("diminished", "seventh");

// compact notation
const minorSecond = interval("m", "2");
const majorSixth = interval("M", "6");
const perfectFourth = interval("P", "4");
const augmentedThird = interval("A", "3");

Learning more about an Interval

import { intervalName } from "twelve-tones";

intervalName(interval("minor", "second")); // => 'minor second'
intervalName(["m", "2"]); // => 'minor second'

const P8 = interval("perfect", "octave");
`A ${P8} is a big jump.`; // => 'A perfect octave is a big jump.'
import { interval, isSameInterval } from "twelve-tones";

const perfectFourth = interval("perfect", "fourth");
const diminishedFifth = interval("diminished", "fifth");

isSameInterval(perfectFourth, diminishedFifth); // => false
isSameInterval(perfectFourth, interval("P", 4)); // => true
import { interval, quality } from "twelve-tones";

quality(interval("P", "8")); // => 'perfect'
quality(interval("M", "3")); // => 'major'
quality(interval("m", "6")); // => 'minor'

quality(interval("diminished", "fourth")); // => -1
quality(interval("A", 2)); // => 1

Transposing pitches

import { pitch, interval } from "twelve-tones";

const fNatural = pitch("F", "♮", 4);
const perfectFifth = interval("perfect", "fifth");
transpose(fNatural, perfectFifth); // => C♮5 (Pitch object)
transpose(fNatural, perfectFifth, "down"); // => B♭4 (Pitch object)

// shorthand notation
transpose(["C", "♮", 3], ["M", "3"], "down"); // => A♭2

By default, transpositions are applied in the up direction. To transpose down, provide 'down' or -1 as a third parameter to transpose.

Advanced quality factors

The quality factor of a diminished or augmented chord can be provided as a number to generate higher orders such as doubly-augmented or triply-diminished:

import { interval, quality } from "twelve-tones";

const triplyDiminishedFifth = interval([-3, "fifth"]);
const octuplyAugmentedThird = interval([+8, "third"]);

quality(triplyDiminishedFifth); // => -3
quality(octuplyAugmentedThird); // => 8

Combining multiple intervals together

Intervals from unison to octave can be built using the above mentioned syntax. When an interval needs to span more than an octave (such as a ninth, or thirteens), use combine to construct greater intervals:

import { combine } from "twelve-tones";

const ninth = combine(['P', '8'], ['M', '2']);

This allows for any interval to be created:

import { interval, combine, transpose } from "twelve-tones";

const P8 = interval('perfect', 'octave');
const A6 = interval('augmented', 'sixth');
const M2 = interval('major', 'second');

const bigInterval = combine(P8, A6, M2);

transpose(['E', '♭', 4], bigInterval, 'up'); // => Pitch (D♯6)

Chords

Commonly used chords can be created using triad or seventhChord:

import { triad, seventhChord } from "twelve-tones";

triad('major'); // Chord object representing a major triad
triad('minor'); // Chord object representing a minor triad

seventhChord('dominant'); // Chord object representing a dominant seventh chord
seventhChord('half-diminished'); // Chord object representing a dominant seventh chord

A Chord object is root-agnostic, until pitch values are extracted with a provided rootnote:

import { triad, pitches } from "twelve-tones";

const aFlatMajor = pitches(triad('major'), ['A', '♭', 4]); // => Pitch[]: A♭4, C♮5, E♭5
const fSharpMinor = pitches(triad('minor'), ['F', '♯', 4]); // => Pitch[]: F♯4, A♯4, C♯5

const cMajorFirstInversion = pitches(triad('major'), ['C', '♮', 4], 1); // => Pitch[]: E♮4, G♮4, C♮5

Behind the scenes

The properties on the Pitch and Interval objects may be confusing.

The easiest way to use twelve-tones is to ignore these properties, and use the utiliy functions as described above, such as pitchName, interval, isSamePitch, etc.

But in case you are interested, here's what the properties represent.

Pitch object structure

A Pitch object is a reference to a specific position on the Circle of Fifths, along with an absolute octave number.

The circlePosition property of a Pitch refers to:

| … | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | … | | - | ------ | ------ | ------ | --------- | --------- | --------- | --------- | --------- | --------- | ------- | ------- | --- | - | | … | A flat | E flat | B flat | C natural | G natural | D natural | A natural | E natural | B natural | F sharp | C sharp | G sharp | … |

expanding infinitely in both directions.

import { pitch } from "twelve-tones";

pitch('A', '♮', 4).circlePosition; // => 3
pitch('A', '♮', 4).octave; // => 4

pitch('A', '♭', 7).circlePosition; // => -3
pitch('A', '♭', 7).octave; // => 7

Interval object structure

An Interval object describes how to jump around on the Circle of Fifths in order to transpose a note by a certain amount.

For example:

  • a major second can be described as: move 2 steps to the right
  • a perfect fourth can be described as: move 1 step to the left
import { interval } from "twelve-tones";

interval('major', 'second').circleShift; // => 2
interval('perfect', 'fourth').circleShift; // => -1

Additionally, an Interval can span multiple octaves, hence the octaveShift property.

  • a perfect fifth requires 1 steps along the circle, but no octave jumps
  • a perfect octave requires no steps along the circle, but 1 octave jump
import { interval } from "twelve-tones";

interval('perfect', 'fifth'); // => { circleShift: 1, octaveShift: 0 }
interval('perfect', 'octave'); // => { circleShift: 0, octaveShift: 1 }