Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 0 additions & 82 deletions .changeset/sequence-and-musicxml-import.md

This file was deleted.

12 changes: 0 additions & 12 deletions .changeset/version-constant.md

This file was deleted.

94 changes: 94 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,99 @@
# musictheoryjs

## 3.2.0

### Minor Changes

- 9b4ce96: A sequence module with drums and tempo maps, MusicXML and rhythm-aware ABC
import, and the analysis deep cuts: Forte set classes, counterpoint
checking, and twelve-tone rows.

**`musictheoryjs/sequence`** — notes placed in time. Streams are timed in
quarter-note beats and convert exactly to MIDI ticks, notation scores, or
seconds:

- Melodies from pitches and durations (`melody`, with rests and cycling
durations) or from rhythm patterns (`patternMelody`), combined in time
with `concatStreams`, `mergeStreams`, `shiftStream`, `loopStream`,
`transposeStream`.
- `arpeggiate` (named contours or explicit index patterns, octave
extension) and `strum` (spread, direction, voices releasing together).
- `compProgression` — Roman numerals in a key to voice-led, rhythm-placed
events in one call; `compChords` for chord lists (with `N.C.` silences);
`bassline` with roots, root–fifth, and a deterministic walking style with
chromatic approach tones.
- Groove: `swing` as a piecewise-linear warp (inner subdivisions bend
proportionally), meter-aware `accent` (correct in irregular meters),
reproducible `humanize`, `gate`, and `rampVelocity` — crescendos and
diminuendos as linear velocity ramps over a beat span.
- `sliceStream` — a time window cut from a stream, truncated at the edges
and re-zeroed so it loops and concatenates (or kept in place with
`keepPosition`).
- Motif transforms: `retrograde`, `invertMelody` (spelled chromatic mirror,
or tonal within a scale), `augment`, and the classical `diatonicSequence`
(chromatic neighbours ride their anchor tone).
- `songForm` expands "AABA" (or named sections) over parts into one
timeline with section boundaries.
- Conversions: `sequenceToMidi` / `midiToSequence` (beats ↔ ticks, exact),
`sequenceToScore` (chords grouped, gaps to rests, triplets kept — refuses
what a score cannot express), `sequenceSeconds`.
- Drum tracks: `GM_DRUMS` names the General MIDI percussion notes, and
`drumPattern` lays drum-machine grids (`"x..X"` strings with accents, or
any rhythm pattern) onto a stream ready for channel-9 MIDI.
- Tempo maps: `sequenceSeconds` and `sequenceToMidi` take beat/BPM points
(each tempo holding until the next), and `midiTempoMap` reads a file's
tempo changes back in beats — so a ritardando survives the whole trip.

**MusicXML import** — `fromMusicXML` in the notation module reads
`score-partwise` and `score-timewise` documents with a dependency-free XML
reader: spelled pitches, chords, ties merged across barlines, multiple
voices via backup/forward, multiple parts, and title/key/time/tempo. The
result is a beat-timed stream per part, ready for the sequence, analysis,
and MIDI layers.

**ABC import reads rhythm** — `fromABC` used to skip durations; now the
tune's body also comes back as the same kind of beat-timed `stream`:
duration factors against the unit note length (`L:`, or the standard's
default from the meter), broken rhythms (`>`, `<`), rests as gaps,
`(p:q:r` tuplet groups, chords stacked at one onset, ties merged into
single events (keeping their accidental across the barline), and the `Q:`
field as `tempo` in quarter-note BPM. `notes` still lists every written
pitch, so existing callers see what they saw before.

**MIDI tempo maps** — a parsed file now keeps every FF 51 tempo event
(`tempoMap`, in tick order), `writeMidi` writes them all back, and
`midiToNoteStream` integrates over them so seconds stay honest through
tempo changes.

**Set theory completed** — `pcsetInvert`, `pcsetComplement`,
`pcsetNormalForm`, `pcsetPrimeForm` (Rahn's convention), and
`pcsetIntervalVector` join the mask primitives; `forteName`,
`fortePrimeForm`, and `forteZMate` cover the full Forte catalog — all 224
set classes, validated structurally in tests.

**Counterpoint checking** — `checkCounterpoint` examines two lines against
the classical rules: parallel fifths and octaves (antiparallels included),
direct fifths and octaves, voice crossing, and voice overlap, each issue
timed and pinned to its notes.

**Twelve-tone rows** — `toneRow`, `rowTransform` (all 48 P/I/R/RI forms),
`rowMatrix`, and `identifyRowForm` for naming which form a passage states.

Also: passing a progression where a key belongs
(`parseProgression("ii7 V7 I", "C major")`) now names the real mistake —
the arguments are swapped — instead of only "invalid key".

### Patch Changes

- 9b4ce96: Fix the exported `VERSION` constant, which reported `"3.0.0"` on 3.0.1, 3.0.2,
and 3.1.0. It is a literal so the bundles stay self-contained, and nothing kept
it in step with `package.json`.

Two changes so it cannot drift again: the `version` script now runs
`scripts/sync-version.ts` immediately after Changesets bumps `package.json`, and
a test asserts the two match — so a release that skips the sync fails CI instead
of shipping a wrong version string.

## 3.1.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "musictheoryjs",
"version": "3.1.0",
"version": "3.2.0",
"description": "A modern, tree-shakable music theory library with first-class support for non-standard tunings and microtonal music.",
"type": "module",
"sideEffects": false,
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ export * from "./notation/index";
export * from "./audio/index";

/** The library version. */
export const VERSION = "3.1.0";
export const VERSION = "3.2.0";
Loading