Skip to content

Commit

Permalink
Use Named. Fix pcset normalized. Small fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
danigb committed Jun 30, 2019
1 parent 2bddeb0 commit 8fab9d7
Show file tree
Hide file tree
Showing 21 changed files with 288 additions and 203 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ distance("C4", "G4"); // => "5P"

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

- [@tonaljs/tonal](/packages/tonal): Note and interval properties, note transposition and distance
- [@tonaljs/tonal](/packages/tonal): Parse notes and intervals, calculate distances and transpositions
- [@tonaljs/midi](/packages/midi): Midi number conversions
- [@tonaljs/note](/packages/note): Note operations (simplify, transposeBy )
- [@tonaljs/interval](/packages/interval): Interval operations (add, simplify, invert)
- [@tonaljs/pcset](/packages/pcset): Pitch class sets properties
- [@tonaljs/mode](/packages/mode): Tonal modes 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/scale](/packages/scale): Scales and its relations
- [@tonaljs/chord](/packages/chord): Chords and its relations
- [@tonaljs/roman-numeral](/packages/roman-numeral): Parse roman numeral symbols

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion packages/chord-dictionary/chord-dictionary.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe("@tonaljs/chord-dictionary", () => {
intervals: ["1P", "3M", "5P"],
aliases: ["M", ""],
chroma: "100010010000",
normalized: "100010010000"
normalized: "100001000100"
});
});
});
32 changes: 20 additions & 12 deletions packages/mode/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# @tonaljs/mode [![npm version](https://img.shields.io/npm/v/@tonaljs/mode.svg?style=flat-square)](https://www.npmjs.com/package/@tonaljs/mode)
# @tonaljs/mode ![tonal](https://img.shields.io/badge/@tonaljs-mode-yellow.svg?style=flat-square) [![npm version](https://img.shields.io/npm/v/@tonaljs/mode.svg?style=flat-square)](https://www.npmjs.com/package/@tonaljs/mode)

[![tonal](https://img.shields.io/badge/@tonaljs-mode-yellow.svg?style=flat-square)](https://www.npmjs.com/browse/keyword/tonal)

`@tonaljs/mode` is a collection of functions to get musical modes
`@tonaljs/mode` greek modes dictionary

## API

Expand All @@ -13,7 +11,7 @@ Given a mode name, returns a Mode object with the following fields:
- name: the mode name
- aliases: alternative mode names
- modeNum: the mode number (0...7)
- pcset: the pcset number
- mode: the mode number
- alt: the alterations
- triad: the triad chord type
- seventh: the seventh chord type
Expand All @@ -27,28 +25,38 @@ mode("major");
// aliases: ["major"]
// intervals: ["1P", "2M", "3M", "4P", "5P", "6M", "7M"]
// modeNum: 0,
// pcset: 2773,
// mode: 2773,
// alt: 0,
// triad: "",
// seventh: "Maj7",
// }
```

### `names() => string[]`
### `entries() => Mode[]`

Rerturn a list of mode names
Return a list of known modes

Example:

```js
names();
entries().map(mode => mode.name);
// => ["ionian", "dorian", "phrygian", "lydian", "mixolydian", "aeolian", "locrian"];
```

### `aliases() => string[]`
## How to?

#### Get notes from a mode?

Return a list of alternative mode names
For example, "A major" mode:

```js
aliases(); // => ["major", "minor"]
import { transpose } from "@tonaljs/tonal";
import { mode } from "@tonaljs/mode";

mode("major").intervals.map(interval => transpose("A", interval));
["A", "B", "C#", "D", "E", "F#", "G#"];
```

## Want more?

Take a look to [@tonal/key]()
24 changes: 16 additions & 8 deletions packages/mode/data.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
// [name, pcset, fifths, triad, seventh, alias?]
type ModeDefinition = [string, number, number, string, string, string?];
export type ModeDefinition = [
number,
number,
number,
string,
string,
string,
string?
];

const DATA: ModeDefinition[] = [
["ionian", 2773, 0, "", "Maj7", "major"],
["dorian", 2902, 2, "m", "m7"],
["phrygian", 3418, 4, "m", "m7"],
["lydian", 2741, -1, "", "Maj7"],
["mixolydian", 2774, 1, "", "7"],
["aeolian", 2906, 3, "m", "m7", "minor"],
["locrian", 3434, 5, "dim", "m7b5"]
[0, 2773, 0, "ionian", "", "Maj7", "major"],
[1, 2902, 2, "dorian", "m", "m7"],
[2, 3418, 4, "phrygian", "m", "m7"],
[3, 2741, -1, "lydian", "", "Maj7"],
[4, 2774, 1, "mixolydian", "", "7"],
[5, 2906, 3, "aeolian", "m", "m7", "minor"],
[6, 3434, 5, "locrian", "dim", "m7b5"]
];

export default DATA;
66 changes: 45 additions & 21 deletions packages/mode/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { chromaToIntervals, EmptyPcset, Pcset } from "@tonaljs/pcset";
import DATA from "./data";
import { Named } from "@tonaljs/tonal";
import DATA, { ModeDefinition } from "./data";

export interface Mode extends Pcset {
readonly name: string;
Expand All @@ -20,28 +21,57 @@ const NoMode: Mode = {
aliases: []
};

const ea: Pcset = NoMode;
const all: Mode[] = DATA.map(toMode);
const index: Record<string, Mode> = {};
all.forEach(mode => {
index[mode.name] = mode;
mode.aliases.forEach(alias => {
index[alias] = mode;
});
});

const NAMES: string[] = [];
const ALIASES: string[] = [];
const MODES: Record<string, Mode> = {};
type ModeLiteral = string | Named;

export function mode(name: string): Mode {
return MODES[name] || NoMode;
/**
* Get a Mode by it's name
*
* @example
* mode('dorian')
* // =>
* // {
* // intervals: [ '1P', '2M', '3m', '4P', '5P', '6M', '7m' ],
* // modeNum: 1,
* // chroma: '101101010110',
* // normalized: '101101010110',
* // name: 'dorian',
* // setNum: 2902,
* // alt: 2,
* // triad: 'm',
* // seventh: 'm7',
* // aliases: []
* // }
*/
export function mode(name: ModeLiteral): Mode {
return typeof name === "string"
? index[name.toLowerCase()] || NoMode
: name && name.name
? mode(name.name)
: NoMode;
}

export function names() {
return NAMES.slice();
}
export function aliases() {
return ALIASES.slice();
/**
* Get a list of all know modes
*/
export function entries() {
return all.slice();
}

DATA.forEach(([name, setNum, alt, triad, seventh, alias], modeNum) => {
function toMode(mode: ModeDefinition): Mode {
const [modeNum, setNum, alt, name, triad, seventh, alias] = mode;
const aliases = alias ? [alias] : [];
const chroma = Number(setNum).toString(2);
const intervals = chromaToIntervals(chroma);
const mode: Mode = {
return {
empty: false,
intervals,
modeNum,
Expand All @@ -54,10 +84,4 @@ DATA.forEach(([name, setNum, alt, triad, seventh, alias], modeNum) => {
seventh,
aliases
};
NAMES.push(mode.name);
MODES[mode.name] = mode;
mode.aliases.forEach(alias => {
MODES[alias] = mode;
ALIASES.push(alias);
});
});
}
85 changes: 48 additions & 37 deletions packages/mode/mode.test.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,57 @@
import { aliases, mode, Mode, names } from "./index";
import { entries, mode } from "./index";

const names = entries().map(m => m.name);

describe("Mode", () => {
test("mode", () => {
expect(mode("ionian")).toEqual({
empty: false,
modeNum: 0,
name: "ionian",
setNum: 2773,
chroma: "101011010101",
normalized: "101011010101",
alt: 0,
triad: "",
seventh: "Maj7",
aliases: ["major"],
intervals: ["1P", "2M", "3M", "4P", "5P", "6M", "7M"]
});
expect(mode("major")).toEqual(mode("ionian"));
});
describe("mode", () => {
test("properties", () => {
expect(mode("ionian")).toEqual({
empty: false,
modeNum: 0,
name: "ionian",
setNum: 2773,
chroma: "101011010101",
normalized: "101011010101",
alt: 0,
triad: "",
seventh: "Maj7",
aliases: ["major"],
intervals: ["1P", "2M", "3M", "4P", "5P", "6M", "7M"]
});
expect(mode("major")).toEqual(mode("ionian"));
});
test("accept Named as parameter", () => {
expect(mode(mode("major"))).toEqual(mode("major"));
expect(mode({ name: "Major" })).toEqual(mode("major"));
});
test("name is case independent", () => {
expect(mode("Dorian")).toEqual(mode("dorian"));
});
test("setNum", () => {
const pcsets = names.map(name => mode(name).setNum);
expect(pcsets).toEqual([2773, 2902, 3418, 2741, 2774, 2906, 3434]);
});

test("pcsets", () => {
const pcsets = names().map(name => mode(name).setNum);
expect(pcsets).toEqual([2773, 2902, 3418, 2741, 2774, 2906, 3434]);
});
test("alt", () => {
const alt = names.map(name => mode(name).alt);
expect(alt).toEqual([0, 2, 4, -1, 1, 3, 5]);
});
test("triad", () => {
const triads = names.map(name => mode(name).triad);
expect(triads).toEqual(["", "m", "m", "", "", "m", "dim"]);
});
test("seventh", () => {
const sevenths = names.map(name => mode(name).seventh);
expect(sevenths).toEqual(["Maj7", "m7", "m7", "Maj7", "7", "m7", "m7b5"]);
});

test("alt", () => {
const alt = names().map(name => mode(name).alt);
expect(alt).toEqual([0, 2, 4, -1, 1, 3, 5]);
});
test("triad", () => {
const triads = names().map(name => mode(name).triad);
expect(triads).toEqual(["", "m", "m", "", "", "m", "dim"]);
});
test("seventh", () => {
const sevenths = names().map(name => mode(name).seventh);
expect(sevenths).toEqual(["Maj7", "m7", "m7", "Maj7", "7", "m7", "m7b5"]);
test("aliases", () => {
expect(mode("major")).toEqual(mode("ionian"));
expect(mode("minor")).toEqual(mode("aeolian"));
});
});

test("names", () => {
expect(names()).toEqual([
expect(names).toEqual([
"ionian",
"dorian",
"phrygian",
Expand All @@ -47,7 +61,4 @@ describe("Mode", () => {
"locrian"
]);
});
test("aliases", () => {
expect(aliases()).toEqual(["major", "minor"]);
});
});
1 change: 1 addition & 0 deletions packages/mode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
],
"types": "dist/index.d.ts",
"dependencies": {
"@tonaljs/tonal": "^3.0.4",
"@tonaljs/pcset": "^3.0.4"
},
"author": "danigb@gmail.com",
Expand Down
Loading

0 comments on commit 8fab9d7

Please sign in to comment.