Contains functions to generate voicings. If you're not sure what voicings are, watch this video.
ES6:
import { Voicing } from "tonal";
Nodejs:
const { Voicing } = require("tonal");
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(
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
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
});
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)
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.
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)