Post-tonal pitch-class set theory for JavaScript and TypeScript: normal order, prime form, interval-class vector, Forte numbers, Z-relations, complement, symmetry, and the full set-class catalog. Typed, zero runtime dependencies, runs in the browser and in Node.
npm install pcsetimport { setClass, primeForm, forte, commonName, intervalVector, sameSetClass } from "pcset";
primeForm([0, 4, 7]); // [0, 3, 7] major triad
primeForm([0, 3, 7]); // [0, 3, 7] minor triad, same set class
intervalVector([0, 4, 7]); // [0, 0, 1, 1, 1, 0]
forte([0, 4, 7]); // "3-11"
commonName([0, 4, 7]); // "major/minor triad (3-11)"
commonName([2, 6, 9]); // "major/minor triad (3-11)" -- any transposition
commonName([0, 2, 4, 6, 8, 10]); // "whole-tone scale (6-35)"
commonName([0, 2, 4, 5, 7, 9, 11]); // "diatonic / major scale (7-35)"
commonName([0, 1, 2, 3, 4]); // null -- no standard name
sameSetClass([0, 4, 7], [0, 3, 7]); // true
setClass([0, 1, 4, 6]);
// {
// pcs: [0, 1, 4, 6],
// normalOrder: [0, 1, 4, 6],
// primeForm: [0, 1, 4, 6],
// forte: "4-z15",
// cardinality: 4,
// intervalVector: [1, 1, 1, 1, 1, 1], // all-interval tetrachord
// complementPrimeForm: [0, 1, 2, 3, 5, 6, 7, 8],
// zPartner: [0, 1, 3, 7], // the other all-interval tetrachord
// transpositionalSymmetry: 1,
// inversionalSymmetry: 0,
// }Pitch classes are integers, C = 0. Inputs may be unsorted, duplicated, or outside 0..11; they are reduced modulo 12.
Post-tonal analysis (prime form, interval-class vectors, Z-relations) is standard material in music theory, but the JavaScript ecosystem has no focused library for it. @tonaljs/pcset, the set module of the dominant JS music library, computes only set membership, subset, and superset; it does not compute normal order, prime form, interval vectors, inversion, complement, or Z-relations. music21 is excellent but is a large Python framework, not usable in a browser. The Python pcsets package was last released in 2007.
pcset fills that gap with a small, correct, dependency-free engine that is easy to embed in interactive theory and pedagogy tools.
| Capability | pcset | @tonaljs/pcset | music21 |
|---|---|---|---|
| Normal order | yes | no | yes |
| Prime form | yes | no | yes |
| Interval-class vector | yes | no | yes |
| Transposition and inversion | yes | partial | yes |
| Complement | yes | no | yes |
| Z-relation detection | yes | no | yes |
| Symmetry degrees | yes | no | yes |
| Full set-class catalog | yes | no | yes |
| Forte set-class numbers | 3 to 9 | no | yes |
| Common set-class names | yes | no | yes |
| Zero runtime dependencies | yes | yes | no |
| Runs in the browser | yes | yes | no |
| Language | TS | JS/TS | Python |
The chroma string and set number use the same encoding as tonal, so the two libraries interoperate.
All functions are pure. Inputs are read-only number arrays; outputs are normalized pitch-class sets (sorted, unique, 0..11).
normalize(pcs)reduces raw integers to a normalized set.normalOrder(pcs)returns the most compact cyclic ordering.primeForm(pcs)returns the canonical set-class representative (Rahn algorithm), starting on 0.intervalVector(pcs)returns the interval-class vector[ic1..ic6].forte(pcs)returns the Forte set-class number (for example "3-11" or "4-z15"), or null.commonName(pcs)returns a widely recognized common name for the set class (for example "whole-tone scale (6-35)"), or null when none is assigned. Transposition- and inversion-invariant.setClass(pcs)returns the fullSetClassInfo(normal order, prime form, interval vector, complement, Z-partner, symmetry).
transpose(pcs, n)transposes by n semitones (Tn).invert(pcs)inverts about pitch class 0 (T0I).invertAround(pcs, axis)inverts about an axis (TnI).complement(pcs)returns the pitch classes not in the set.
equals(a, b),isSubsetOf(a, b),isSupersetOf(a, b)isTranspositionOf(a, b),isInversionOf(a, b),sameSetClass(a, b)isZRelatedTo(a, b)
transpositionalSymmetry(pcs),inversionalSymmetry(pcs)
toChroma(pcs),fromChroma(chroma),toNumber(pcs),fromNumber(num)catalog()returns the complete set-class catalog (224 classes) as aMapkeyed by prime form.catalogEntry(pcs)looks up the catalog entry for a set.
Prime form here follows the Rahn algorithm (the convention used by Straus): take the more left-packed of the set's normal order and its inversion's normal order, each transposed to 0. For the small number of set classes where Forte and Rahn disagree (for example 5-20, 6-31, 7-20), this returns the Rahn form.
Forte numbers are provided for all set classes of cardinalities 3 to 9, including the 50 hexachords (cardinality 6), with the z designation marking Z-related classes (for example "6-z44"). Because a set class and its complement share a Forte ordinal, the labels for cardinalities 7 to 9 are derived from those for 3 to 5. The hexachord labels are cross-checked against the library's own catalog: the tests confirm that the z marking matches the catalog's interval-vector Z-relation detection for every hexachord, that all 50 classes are covered, and that each label is unique.
- Abstract subset and superset relations between set classes.
- Generalization to mod-n universes for microtonal work.
npm run examplenpm testThe suite covers known prime forms and interval vectors, structural checks against the full set-class catalog (counts per cardinality, complement and Z-relation consistency), and property-based invariants (transposition and inversion preserve set class and interval vector, prime form is idempotent, encodings round-trip).
Issues and pull requests are welcome. See CONTRIBUTING.md.
MIT. See LICENSE.
