Music theory for MIDI note events: recover the harmony from notes, and write new parts against that same reading.
One specification, a pure TypeScript reference implementation and a C++17 core under it, reachable from C++, WebAssembly, Node, Python and the command line. Every surface gives the same results and the same errors, and the surfaces over the core give the same floating-point bits on every platform.
Documentation · Getting started · Packages and surfaces
- Harmony from notes. Chord and key detection, Roman numerals, cadences, modulation, form. Analysis
- Parts against the harmony. Progressions, bass, counter-melody, drums, motifs, seeded and reproducible. Generation
- Theory vocabulary. Notes, intervals, scales, chords, voicing, part-writing and counterpoint checks. Harmony
- Playability. Instrument profiles, transposition and range checks. Instruments
- Evidence in answers. Each reading carries its rationale and the readings it turned down; an undecidable question comes back
null.
| Surface | Package | Page |
|---|---|---|
| TypeScript (reference) | @libraz/libcantus |
ts/ |
| C++ | CMake package cantus |
C++ core |
| WebAssembly | @libraz/libcantus-wasm |
bindings/wasm/ |
| Node native | @libraz/libcantus-node (built from source) |
bindings/node/ |
| Python | libcantus |
bindings/python/ |
| Command line | cantus |
Command line |
The TypeScript package is synchronous, dependency-free and tree-shakeable. The other surfaces call the C++ core and differ from it only in small, documented ways (C++ core and surface differences).
Each example reads the chord of C, E and G.
TypeScript, Node.js 22 or later:
yarn add @libraz/libcantusimport { detectChordBest } from '@libraz/libcantus';
detectChordBest([60, 64, 67]); // { rootPc: 0, quality: 'maj', intervals: [0, 4, 7] }WebAssembly, ESM only; the same API and types:
yarn add @libraz/libcantus-wasmimport { detectChordBest } from '@libraz/libcantus-wasm';
detectChordBest([60, 64, 67]);Code that imports @libraz/libcantus can switch to it without edits, through a package-manager or bundler alias: see Switching between pure TypeScript and WebAssembly.
Node native, from a checkout (make build-node):
import { detectChordBest } from '@libraz/libcantus-node';
detectChordBest([60, 64, 67]);Python, 3.10 or later:
pip install libcantusimport libcantus
libcantus.detect_chord_best([60, 64, 67])Command line, a release asset from GitHub:
cantus detectChordBest '[[60, 64, 67]]'C++, CMake 3.24 and a C++17 compiler:
include(FetchContent)
FetchContent_Declare(cantus GIT_REPOSITORY https://github.com/libraz/libcantus.git GIT_TAG main)
FetchContent_MakeAvailable(cantus)
target_link_libraries(app PRIVATE cantus::cantus)#include <cantus/cantus.h>
auto matches = cantus::detect_chord({60, 64, 67});find_package(cantus) against an installed prefix and add_subdirectory work the same way. Runnable versions of these examples are in examples/ and run with make examples; the browser example there is a bundler template that make examples does not run.
make build # C++ core, command-line tool and tests in build/
make test-cxx # run the C++ tests
make wasm # WebAssembly package (needs Emscripten)
make build-node # Node-API addon
make build-shared # shared library for the Python binding
make examples # build and run the examples in examples/ (not the browser one)- Learn: Primer for the music theory, Introduction, Getting started, and Use cases for complete flows.
- Guides: Analysis, Generation, Harmony, Voicing, Rhythm and groove and the other domain pages listed in API reference.
- Surfaces: Packages and surfaces, C++ core, Python, Command line.
- Reference: Errors and validation, Glossary, Questions and limitations.
The pages are also in Japanese under docs/ja/. Contributor rules are in CONTRIBUTING.md.
- No I/O, notation or audio. No MIDI file reader or writer, no score rendering, no audio analysis, no playback. Bring your own parser and hand it note events. For the layer below, libsonare covers audio analysis, mastering, synthesis and SMF I/O; the two share no code and neither requires the other.
- No microtonal analysis. Frequencies, cents and just-intonation ratios live in
core, but everything above the pitch layer runs on twelve pitch classes. - No rāga or maqām-style modal grammars.
WORLD_SCALESrecords the pitch material a tradition names, not the grammar built on it. - No corpus. Nothing is bundled to run statistics over.