Skip to content

Commit

Permalink
New module structure with backwards compatibility. New chord-detect m…
Browse files Browse the repository at this point in the history
…odule. (#139)

- New module structure: Tonal is renamed to Core. Modules renamed to Tonal
- All modules exports default for easy import
- Rename chord-dictionary to chord-type and scale-dictionary to scale-type
- Rename array to collection (to avoid name classing with native Array)
  • Loading branch information
danigb authored Mar 11, 2020
1 parent 7cc34c4 commit 16b5c63
Show file tree
Hide file tree
Showing 87 changed files with 2,590 additions and 1,241 deletions.
59 changes: 39 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,21 @@ It uses a functional programing style: all functions are pure, there is no data
## Example

```js
import { Note, Interval } from "@tonaljs/tonal";
import { Note, Interval, Scale } from "@tonaljs/tonal";

Note.note("A4").midi; // => 60
Note.note("a4").freq; // => 440
Note.note("c#2").accidentals; // => '#'
Note.note("x").midi; // => undefined
Note.midi("A4"); // => 60
Note.freq("a4").freq; // => 440
Note.accidentals("c#2"); // => '#'
Note.transpose("C4", "5P"); // => "G4"
Interval.interval("5P").semitones; // => 7
Interval.semitones("5P"); // => 7
Interval.distance("C4", "G4"); // => "5P"
Scale.get("C major").notes; // =>["C", "D", "E", "F", "G", "A", "B"];
```

## Install

Install all packages at once:

```bash
npm install --save @tonaljs/tonal
```
Expand Down Expand Up @@ -60,37 +62,53 @@ Grab the [minified browser ready version](https://raw.githubusercontent.com/tona

#### Bundle size

`@tonaljs/tonal` includes all published modules. Although tonal it is small, you can reduce bundle sizes by importing the modules individually, or even only the functions you need:
`@tonaljs/tonal` includes all published modules.

```
npm i @tonaljs/core
Although the final bundle it is small (less than 9kb minified and gzipped), you can reduce bundle sizes by installing the modules individually, and importing the functions you need:

```bash
npm i @tonaljs/note
```

```js
import { transpose } from "@tonaljs/core";
import { transpose } from "@tonaljs/note";
transpose("A4", "P5");
```

## Documentation

The API documentation lives inside README.md file of each module:
Generally, you just need to install:

- [@tonaljs/tonal](/packages/tonal): All modules bundled in one package

The API documentation lives inside README.md file of each module

#### Notes and intervals

- [@tonaljs/note](/packages/note): Note operations (simplify, transposeBy )
- [@tonaljs/midi](/packages/midi): Midi number conversions
- [@tonaljs/scale](/packages/scale): Scales and its relations
- [@tonaljs/chord](/packages/chord): Chords and its relations
- [@tonaljs/interval](/packages/interval): Interval operations (add, simplify, invert)
- [@tonaljs/pcset](/packages/pcset): Pitch class sets properties
- [@tonaljs/mode](/packages/mode): Parse (greek) tonal modes (ionian, dorian, ...)
- [@tonaljs/scale-dictionary](/packages/scale-dictionary): A dictionary of scales
- [@tonaljs/chord-dictionary](/packages/chord-dictionary): A dictionary of chords
- [@tonaljs/key](/packages/key): Major and minor keys scales and chords
- [@tonaljs/abc-notation](/packages/abc-notation): Parse ABC notation notes

#### Scales and chords

- [@tonaljs/scale](/packages/scale): Scales
- [@tonaljs/chord](/packages/chord): Chords
- [@tonaljs/scale-type](/packages/scale-type): A dictionary of scales
- [@tonaljs/chord-type](/packages/chord-type): A dictionary of chords
- [@tonaljs/pcset](/packages/pcset): Pitch class sets. Compare note groups.
- [@tonaljs/mode](/packages/mode): A dictionary of Greek modes (ionian, dorian...)

#### Keys, chord progressions

- [@tonaljs/key](/packages/key): Major and minor keys, it's scales and chords
- [@tonaljs/progression](/packages/progression): Chord progressions
- [@tonaljs/roman-numeral](/packages/roman-numeral): Parse roman numeral symbols
- [@tonaljs/abc-notation](/packages/abc-notation): Parse ABC notation notes

#### Utilities

- [@tonaljs/core](/packages/core): Core functions (note, interval, transpose and distance)
- [@tonaljs/array](/packages/array): Array manipulation
- [@tonaljs/collection](/packages/collection): Utility functions to work with collections (range, shuffle, permutations)
- [@tonaljs/range](/packages/range): Create note ranges

## Contributing
Expand All @@ -106,6 +124,7 @@ This library takes inspiration from other music theory libraries:
- MusicKit: https://github.com/benzguo/MusicKit
- Music21: http://web.mit.edu/music21/doc/index.html
- Sharp11: https://github.com/jsrmath/sharp11
- python-mingus: https://github.com/bspaans/python-mingus

## Projects using tonal

Expand Down
8 changes: 4 additions & 4 deletions docs/migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

## From version 3 to 4

### `chord-dictionary`
### `chord-type`

- `ChordDictionary.chordType` renamed to `ChordDictionary.get`
- `ChordType.chordType` renamed to `ChordType.get`

### `scale-dictionary`
### `scale-type`

- `ScaleDictionary.scaleType` renamed to `ScaleDictionary.get`
- `ScaleType.scaleType` renamed to `ScaleType.get`

## From version 2 to 3

Expand Down
41 changes: 27 additions & 14 deletions packages/abc-notation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,50 @@

> Convert note names between scientific and abc notation
## References
## Usage

ES6:

- - [ABC Notation](https://en.wikipedia.org/wiki/ABC_notation)
```js
import { AbcNotation } from "@tonaljs/tonal";
```

nodejs:

```js
const { AbcNotation } = require("@tonaljs/tonal");
```

## API

#### `abcToScientificNotation(noteNameInAbc: string) => string`

```js
abcToScientificNotation("c"); // => "C5"
AbcNotation.abcToScientificNotation("c"); // => "C5"
```

#### `scientificToAbcNotation(noteNameInScientific: string) => string`

```js
scientificToAbcNotation("C#4"); // => "^C"
AbcNotation.scientificToAbcNotation("C#4"); // => "^C"
```

## How to?
#### `transpose(note: string, interval: string) => string`

#### Transpose notes in abc notation
Transpose an note in abc notation:

```js
import { transpose } from "@tonaljs/note";
import {
abcToScientificNotation,
scientificToAbcNotation
} from "@tonal/abc-notation";
AbcNotation.transpose("=C", "P19"); // => "g'"
```

const transposeAbc = (note, interval) =>
scientificToAbcNotation(abcToScientificNotation(note), interval);
#### `distance(from: string, to: string) => string`

transposeAbc("c", "P5");
Find the interval between two notes in abc notation:

```js
AbcNotation.distance("=C", "g"); // => "12P"
```

## References

- [ABC Notation](https://en.wikipedia.org/wiki/ABC_notation)
26 changes: 12 additions & 14 deletions packages/abc-notation/abc-notation.test.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
import {
abcToScientificNotation,
scientificToAbcNotation,
tokenize,
transpose
} from "./index";
import AbcNotation from "./index";

describe("@tonaljs/abc-notation", () => {
test("tokenize", () => {
expect(tokenize("C,',")).toEqual(["", "C", ",',"]);
expect(tokenize("g,,'")).toEqual(["", "g", ",,'"]);
expect(tokenize("")).toEqual(["", "", ""]);
expect(tokenize("m")).toEqual(["", "", ""]);
expect(tokenize("c#")).toEqual(["", "", ""]);
expect(AbcNotation.tokenize("C,',")).toEqual(["", "C", ",',"]);
expect(AbcNotation.tokenize("g,,'")).toEqual(["", "g", ",,'"]);
expect(AbcNotation.tokenize("")).toEqual(["", "", ""]);
expect(AbcNotation.tokenize("m")).toEqual(["", "", ""]);
expect(AbcNotation.tokenize("c#")).toEqual(["", "", ""]);
});

test("transpose", () => {
expect(transpose("=C", "P19")).toEqual("g'");
expect(AbcNotation.transpose("=C", "P19")).toEqual("g'");
});
test("distance", () => {
expect(AbcNotation.distance("=C", "g")).toEqual("12P");
});

test("toNote", () => {
const ABC = ["__A,,", "_B,", "=C", "d", "^e'", "^^f''", "G,,''", "g,,,'''"];
const SCIENTIFIC = ["Abb2", "Bb3", "C4", "D5", "E#6", "F##7", "G4", "G5"];
expect(ABC.map(abcToScientificNotation)).toEqual(SCIENTIFIC);
expect(ABC.map(AbcNotation.abcToScientificNotation)).toEqual(SCIENTIFIC);
});

test("toAbc", () => {
const SCIENTIFIC = ["Abb2", "Bb3", "C4", "D5", "E#6", "F##7", "G#2", "Gb7"];
const ABC = ["__A,,", "_B,", "C", "d", "^e'", "^^f''", "^G,,", "_g''"];
expect(SCIENTIFIC.map(scientificToAbcNotation)).toEqual(ABC);
expect(SCIENTIFIC.map(AbcNotation.scientificToAbcNotation)).toEqual(ABC);
});
});
14 changes: 13 additions & 1 deletion packages/abc-notation/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { note, transpose as tr } from "@tonaljs/core";
import { distance as dist, note, transpose as tr } from "@tonaljs/core";

const fillStr = (character: string, times: number) =>
Array(times + 1).join(character);
Expand Down Expand Up @@ -63,3 +63,15 @@ export function scientificToAbcNotation(str: string): string {
export function transpose(note: string, interval: string): string {
return scientificToAbcNotation(tr(abcToScientificNotation(note), interval));
}

export function distance(from: string, to: string): string {
return dist(abcToScientificNotation(from), abcToScientificNotation(to));
}

export default {
abcToScientificNotation,
scientificToAbcNotation,
tokenize,
transpose,
distance
};
60 changes: 2 additions & 58 deletions packages/array/README.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,3 @@
# @tonaljs/array ![tonal](https://img.shields.io/badge/@tonaljs-array-yellow.svg?style=flat-square) [![npm version](https://img.shields.io/npm/v/@tonaljs/array.svg?style=flat-square)](https://www.npmjs.com/package/@tonaljs/array)
# deprecated: @tonaljs/array

> A collection of functions to create and manipulate arrays of notes or intervals.
## API

### `range(from: number, to: number) => number[]`

Creates a numeric range:

```js
range(-2, 2); // => [-2, -1, 0, 1, 2]
range(2, -2); // => [2, 1, 0, -1, -2]
```

### `rotate(times: number, array: any[]) => any[]`

Rotate an array a number of times:

```js
rotate(1, [1, 2, 3]); // => [2, 3, 1]
```

### `sortedNoteNames(array: any[]) => string[]`

Sort an array of note names in ascending order. Pitch classes are listed before notes.
Any string that is not a note is removed.

```js
sortedNoteNames(["c2", "c5", "c1", "c0", "c6", "c"]);
// => ['C', 'C0', 'C1', 'C2', 'C5', 'C6']
sortedNoteNames(["c", "F", "G", "a", "b", "h", "J"]);
// => ['C', 'F', 'G', 'A', 'B']
```

### `sortedUniqNoteNames(array: any[]) => string[]`

Return a list of sorted note names with duplications removed.

### `shuffle(array: any[]) => any[]`

Randomizes the order of the specified array in-place, using the Fisher–Yates shuffle.

### `permutations(array: any[]) => any[][]`

Get all permutations of an array

```js
permutations(["a", "b", "c"])) // =>
// =>
// [
// ["a", "b", "c"],
// ["b", "a", "c"],
// ["b", "c", "a"],
// ["a", "c", "b"],
// ["c", "a", "b"],
// ["c", "b", "a"]
// ]
```
Renamed to [`@tonaljs/collection`](/packages/collection)
File renamed without changes.
34 changes: 34 additions & 0 deletions packages/chord-detect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# @tonaljs/chord-detect ![tonal](https://img.shields.io/badge/@tonaljs-chord-detect-yellow.svg?style=flat-square) [![npm version](https://img.shields.io/npm/v/@tonaljs/chord-detect.svg?style=flat-square)](https://www.npmjs.com/package/@tonaljs/chord-detect)

## Usage

With ES6 `import`:

```js
import { Chord } from "@tonaljs/tonal";
```

With ES5 `require`:

```js
const { Chord } = require("@tonaljs/tonal");
```

Standalone:

```js
import { detect } from "@tonaljs/chord-detect";
```

## API

### `Chord.detect(notes: string[]) => string[]`

Examples:

```js
Chord.detect(["D", "F#", "A", "C"]); // => ["D7"]
Chord.detect(["F#", "A", "C", "D"]); // => ["D7/F#"]
Chord.detect(["A", "C", "D", "F#"]); // => ["D7/A"]
Chord.detect(["E", "G#", "B", "C#"]); // => ["E6", "C#m7/E"]
```
15 changes: 15 additions & 0 deletions packages/chord-detect/chord-detect.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// tslint:disable-next-line: no-implicit-dependencies
import { detect } from "./index";

describe("@tonal/chord-detect", () => {
test("detect", () => {
expect(detect(["D", "F#", "A", "C"])).toEqual(["D7"]);
expect(detect(["F#", "A", "C", "D"])).toEqual(["D7/F#"]);
expect(detect(["A", "C", "D", "F#"])).toEqual(["D7/A"]);
expect(detect(["E", "G#", "B", "C#"])).toEqual(["E6", "C#m7/E"]);
});

test("edge cases", () => {
expect(detect([])).toEqual([]);
});
});
Loading

0 comments on commit 16b5c63

Please sign in to comment.