@tonaljs/voicing
v5.1.0
Published
Voicings and Voice Leading for Chords
Downloads
2,482
Maintainers
Readme
@tonaljs/voicing
Contains functions to generate voicings. If you're not sure what voicings are, watch this video.
Usage
ES6:
import { Voicing } from "tonal";
Nodejs:
const { Voicing } = require("tonal");
API
Voicing.search
Voicing.search(chord: string, range?: [string, string], dictionary?: VoicingDictionary): string[][]
This method returns all possible voicings of the given chord, inside the given range, as defined in the dictionary:
Voicing.search("C^7", ["E3", "D5"], { "^7": ["3M 5P 7M 9M", "7M 9M 10M 12P"] });
/* => [
['E3', 'G3', 'B3', 'D4'],
['E4', 'G4', 'B4', 'D5'],
['B3', 'D4', 'E4', 'G4'],
] */
The VoicingDictionary param uses the format of @tonaljs/voicing-dictionary. Instead of defining your own, you could also use an existing dictionary from there:
import { VoicingDictionary } from "@tonaljs/voicing-dictionary";
Voicing.search("C^7", ["E3", "D5"], VoicingDictionary.lefthand);
/* => [
['E3', 'G3', 'B3', 'D4'],
['E4', 'G4', 'B4', 'D5'],
['B3', 'D4', 'E4', 'G4'],
] */
If no range and/or dictionary is given, there is a fallback to default values (look for defaultRange / defaultDictionary):
Voicing.search("C^7");
/* => [
['E3', 'G3', 'B3', 'D4'],
['E4', 'G4', 'B4', 'D5'],
['B3', 'D4', 'E4', 'G4'],
] */
Voicing.get
Voicing.get(
chord: string,
range?: [string, number],
dictionary?: VoicingDictionary,
voiceLeading?: VoiceLeading,
lastVoicing?: string[]
) => string[];
Returns the best voicing for chord inside the given range, as contained in the dictionary, using voiceLeading to decide which voicing to pick after lastVoicing. Internally calls Voicing.search to generate the available voicings:
Voicing.get("Dm7");
/* ['F3', 'A3', 'C4', 'E4']); */
Voicing.get("Dm7", ["F3", "A4"], lefthand, topNoteDiff);
/* ['F3', 'A3', 'C4', 'E4']; */
const last = ["C4", "E4", "G4", "B4"];
Voicing.get("Dm7", ["F3", "A4"], lefthand, topNoteDiff, last);
/* ['C4', 'E4', 'F4', 'A4']; */ // => A4 is closest to B4
Optional: Voicing.analyze
export declare function analyze(voicing: string[]): {
topNote: string;
bottomNote: string;
midiAverage: number;
};
Returns some useful info on the given voicing:
expect(Voicing.analyze(["C4", "E4", "G4", "B4"])).toEqual({
topNote: "B4",
bottomNote: "C4",
midiAverage: 85.4, // did not check :)
// many more values possible
});
Optional: Voicing.analyzeTransition
export declare function analyzeTransition(
from: string[],
to: string[]
): {
topNoteDiff: number;
bottomNoteDiff: number;
movement: number;
};
Returns some useful info on the given voice transition
expect(
Voicing.analyzeTransition(["C4", "E4", "G4", "B4"], ["D4", "F4", "A4", "C5"])
).toEqual({
topNoteDiff: 1,
bottomNoteDiff: 2,
movement: 5,
});
Could also use intervals instead of semitones (but semitones are easier to compare)
Optional: Voicing.intervalSets
export declare function intervalSets(
chordSymbol: string,
dictionary: VoicingDictionary
);
Get possible interval sets for given chord in given dictionary:
expect(Voicing.intervalSets("M7", lefthand)).toEqual([
["3M 5P 7M 9M", "7M 9M 10M 12P"],
]);
// could also be used with chord symbol (ignore root)
expect(Voicing.intervalSets("CM7", lefthand)).toEqual([
["3M 5P 7M 9M", "7M 9M 10M 12P"],
]);
Note that it works, even if the chord symbol "M7" is just an alias of the "^7" symbol used in the dictionary.
Optional: Voicing.searchSets
export declare function searchSets(
intervalSets: string[][],
range: string[],
root: string
);
Renders all sets of notes that represent any of the interval sets inside the given range, relative to the root:
expect(
Voicing.searchSets(
[
["1P", "3M", "5P"],
["3M", "5P", "8P"],
],
["C3", "G4"],
"C"
)
).toEqual([
["C3", "E3", "G3"],
["E3", "G3", "C4"],
["C4", "E4", "G4"],
]);
changes:
- renamed to searchSets (similar to Voicing.search)