Tonal version 3 is a complete rewrite of the library in Typescript.
The new features are:
- Simplified and more coherent API
- Type definitions for all modules
- Better documentation
Unfortunately there are a lot of breaking changes:
To avoid mistakes (and have a better npm home) from v3 the npm packages are namespaced.
So instead of:
const tonal = require("tonal");
// or
import * as tonal from "tonal";
Now we have to:
const tonal = require("@tonaljs/tonal");
// or
import * as tonal from "@tonaljs/tonal";
In version 2 tonal
was a facade for the modules, so dependencies between modules were not clear. Moreover, same functions were exported by different modules.
This is not longer true in v3
In version 2 tonal
was a facade for the rest of the modules:
// this is not longer valid in v3
import { Note } from "tonal";
Now, @tonaljs/tonal
module contains just four functions:
import { note, interval, transpose, distance } from "@tonaljs/tonal";
Instead of:
// v2
import { midiToNote } from "tonal-note";
You will find the function at:
// v3
import { midiToNoteName } from "@tonaljs/midi";
In v2 some functions were exported in several places (like Tonal.transpose
and Note.transpose
). That made the API hard to understand.
Now, every public function is documented in it's own module.
The module architecture is easier to grasp:
TODO: diagram of tonal modules
Lot of changes, but as a positive side effect, the library API surface is smaller so code and documentation are easier to write and maintain.
Now functions falls in two catergories:
- Parsers: takes a name of something (string) and return an object with properties. Examples of that functions are: note, interval, pcset, scaleType, chordType, scale, chord, mode. All of the returning objects has the properties
empty
(boolean) and name (string, "" indicating no value) - Operations: takes one or more names and return a new name. It always work with strings (no objects). Invalid results are represented with empty strings "". Examples: transpose, distance, substract
First of all, lot of functions are gone, like oct
, accToAlt
, and other utility functions (some still exists, but are considered private)
Some functions in v2 could be partially applied:
// valid in v2 and v3
transpose(note, interval);
// not valid in v3
tranpose(note)(interval);
This optional partial application made code unnecessarily complex and, with Typescript types, much harder to understand or write.
For this reason optional partial application are not possible in v3. Most of the functions needs all parameters to execute.
However, there are some execptions to make the API easier to use. In that cases, partial application is obligatory:
// valid in v2 and v3
isSubsetOf(set1)(set2); // => true
// not valid in v3
isSubsetOf(set1, set2);
If you need curry 🍛, use an utility library like lodash)
API documentation are now handwritten and it's inside each module README.md file.
No tonal function returns a null
anymore. For property objects (like Note, or Scale) you can test for the empty
property:
note("hello"); // => { empty: true, name: '' }
interval("bye"); // => { empty: true, name: '' }
scaleType("unknown"); // => { empty: true, name: '' }
This is more important in functions that returns strings (like transpose
):
All functions that returns an string, returns an empty string to indicate invalid params:
// in v2
transpose("C4", "hello"); // => null
// in v3
transpose("C4", "hello"); // => ''