Lab

pitch

Named scales from @audio-ui/engine: the steps of each scale, the pitch classes a scale on a root keeps, whether a pitch is in it and the nearest one that is, and the scale as a piano roll reads it.

pnpm add @audio-ui/engine
import { cents, midiToHz, detectKeys, inScale, nearestInScale, /* … */ } from "@audio-ui/engine/pitch";
Used byarrangement, use-pitch, use-synth-voices, voice-pool
audio.js@audio/mir-key, @audio/note
ExportKindWhat it is
centsfunctionA pitch's frequency, A4 at 440 Hz unless told.
midiToHzfunctionA pitch's frequency, A4 at 440 Hz unless told.
detectKeysfunctionThe keys notes are likeliest in, likeliest first, at most count: each pitch class weighed by how long it sounds, against the major and minor key profiles of @audio/mir-key (Krumhansl-Schmuckler).
KeyNoteinterfaceWhat a key is read from: a note's pitch and how long it lasts, in any unit.
inScalefunctionWhether a MIDI pitch is in a scale.
nearestInScalefunctionThe pitch in a scale nearest pitch: itself when it is in it, else the nearest one, the lower of two as near.
rollScalefunctionA scale as a piano roll reads it: its pitch classes and its root, what @audio-ui/core/piano-roll takes.
SCALESconstThe steps of each scale, as semitones above the root.
ScaleinterfaceA scale on a root: C major is { name: "major", root: 0 }.
ScaleNametypeThe name of a scale of SCALES.
scalePitchClassesfunctionThe pitch classes a scale keeps, from 0 (C) to 11 (B), in order.

Usage

Pitches are MIDI note numbers, 60 being middle C. A Scale is a name of SCALES on a root pitch class, 0 being C:

import { inScale, nearestInScale, rollScale, scalePitchClasses } from "@audio-ui/engine/pitch";

const aMinor = { name: "minor", root: 9 };

scalePitchClasses(aMinor); // [0, 2, 4, 5, 7, 9, 11]
inScale(61, aMinor); // false: C# is not in A minor
nearestInScale(61, aMinor); // 60: of two as near, the lower
rollScale(aMinor); // { pitchClasses: [0, 2, 4, 5, 7, 9, 11], root: 9 }

SCALES holds the steps of each scale as semitones above its root: chromatic, the major and minor scales (natural, harmonic, melodic), the two pentatonics, the blues, the whole-tone scale and the modes (dorian, phrygian, lydian, mixolydian, locrian). The tables and the snapping are @audio/note's, with the three modes it does not list added.

On a piano roll

A piano roll knows a scale only as the pitch classes it keeps and its root, a RollScale: it shades the rows out of the scale, folds onto it and fits notes into it without knowing any scale by name. rollScale(scale) gives a named scale in that shape:

const scale = useMemo(() => rollScale({ name: "dorian", root: 2 }), []);

<PianoRoll.Root scale={scale} />;

Keys

detectKeys(notes, count, audio) gives the keys a set of notes is likeliest in, likeliest first, at most count (3 unless told): each pitch class weighed by how long it sounds against the major and minor key profiles of @audio/mir-key. audio adds the sound of recordings, a weight per pitch class such as an audioChroma times the seconds it plays. One part alone is often ambiguous, as a bass line is: pass every part of the song.

import { detectKeys } from "@audio-ui/engine/pitch";

detectKeys(notes.map(({ pitch, length, muted }) => ({ pitch, length, muted })));
// [{ name: "minor", root: 9 }, { name: "major", root: 0 }, …]

Notes and frequencies

midiToHz(pitch) is a pitch's frequency, A4 at 440 Hz unless told, and cents(frequency) the nearest note to a frequency and how far off it is: { midi, name, hz, cents }, name with its octave, as "A#4", and cents positive when sharp. Both are @audio/note's.

A pitch's name and whether it is a black key are the keyboard's own: pitchName, pitchClassName and isBlackKey are in @audio-ui/core.

Built by Ouest Labs, the source code is available on GitHub.
RSS