# Voicings

This document describes the way to find voicings for chords.

## Definition

A Voicing is a ordered collection of absolute notes that represent a certain chord. E.g. the notes *[D3 F3 A3 C3]* could be a voicing of a *D-7* chord. Another representation could be *[A3 C3 D3 F3]*.

## Degrees

Each note (pitch class) of a voicing plays a certain role in representing a chord. In the above example the notes play the following roles in a D-7 chord:

- D: first degree
- F: third degree
- A: fifth degree
- C: seventh degree

Some degrees are more important than others. For example the third and seventh degrees are more important than the fifths. Here is an overview of the degrees (in tertian order):

- 1st: root note. commonly played in the bass.
- 3rd: defines quality of chord (minor or major)
- 5th: supports the root. Can be omitted.
- 7th: defines quality of a 7th chord.
- 9th: color/tension
- 11th: color/tension
- 13th: color/tension

This means, for a triad the most important degrees are 1 and 3, and for a seventh chord 1, 3 and 7.
3 and 7 are also called guide tones.

## General Voicing Rules

see https://www.youtube.com/watch?v=qNff0NZiXC8
or http://www.thejazzpianosite.com/jazz-piano-lessons/jazz-chord-voicings/chord-voicing-rules/

- Always play guide tones.
- 1 and 5 can be omitted.
- 9 11 and 13 can be added as tensions

### Interval Structure / Consonance

Even if playing the same notes (pitch classes), the tension of the resulting sound can differ, depending on the interval structure. Some intervals create higher tension (dissonant) than others (consonant):

consonant: 5P, 4P, 3M, 3m
dissonant: 5d, 2m, 2M, 9m

generally, stacking thirds leads to more consonant voicings than stacking seconds. Quartal voicings often offer a combination of both consonant and dissonant intervals.

Idea: write function that calculates all interelated intervals in a voicing + tells how consonant/dissonant the sound will be.

### General Interval Rules

1. Avoid using too many 3rds (this is too boring)
2. Using 4ths and tritones creates a more ‘open’ and ‘harmonically ambiguous’ sound
3. Use wider intervals at the bottom (to avoid muddiness)
4. Play dissonant intervals in the middle
5. Play a consonant interval like a 3rd or 4th between the two highest notes
6. Avoid ‘doubling’ notes within the chords, except the top note which can be doubled (otherwise the chord sounds lopsided)
7. Keep all intervals smaller than a Perfect 5th, except the interval between the two bottom notes that can be wider (this ensures what you’re  playing sounds like a single whole chord rather than two chords played simultaneously but far apart from each other)

## Finding valid voicings

### Goals

- Avoid defining fixed sets of voicings for each chord.
- Be able to control tension.

The tonal-chord package contains the basic structure of all common chord symbols. So Voicings can be generated by altering the order of tonals output. see [Chord#notes](http://danigb.github.io/tonal/api/module-Chord.html#.notes).

### Bruteforcing Combinations

One idea to find out voicings could be to generate all possible orderings of the outputted notes.

A triad has 6 different combinations (3 * 2 * 1).

A 7th chord has 24 different orderings (4 * 6).

A 9th chord 120 (5 * 24).

An 11th chord 720 (6 * 120).

A 13th chord 5040 (7 * 720).

#### Bruteforce algorithm

The following recursive algorithm finds all combinations of an array:

```js
export function permutateArray(array: any[]) {
    if (array.length === 1) { return array; }
    return array.reduce((combinations, el) => [
        ...combinations,
        ...permutateArray(array.filter(e => e !== el))
            .map(subcombinations => ([el, ...subcombinations]))
    ], []);
}
```

For example Cmaj7:

```js
permutateArray(Chord.notes("Cmaj7"))
```

outputs

```js
[
    ["C", "E", "G", "B"],
    ["C", "E", "B", "G"], // 7
    ["C", "G", "E", "B"], // 7
    ["C", "G", "B", "E"], // 7
    ["C", "B", "E", "G"], // 7
    ["C", "B", "G", "E"], // 7
    ["E", "C", "G", "B"], // 7
    ["E", "C", "B", "G"], // 7
    ["E", "G", "C", "B"], // 7
    ["E", "G", "B", ""],
    ["E", "B", "C", "G"], // 7
    ["E", "B", "G", "C"], // 7
    ["G", "C", "E", "B"], // 7
    ["G", "C", "B", "E"], // 7
    ["G", "E", "C", "B"], // 7
    ["G", "E", "B", "C"], // 7
    ["G", "B", "C", ""],
    ["G", "B", "E", "C"], // 7
    ["B", "C", "E", "G"]
    ["B", "C", "G", "E"], // 7
    ["B", "E", "C", "G"], // 7
    ["B", "E", "G", ""],
    ["B", "G", "C", "E"], // 7
    ["B", "G", "E", "C"] // 7
]
```

The notes are now interpreted as being stacked above in the most compact way.

#### Sorting out problematic voicings

Many combinations are bad, meaning they contradict, the rules "General Interval Rules" above. Rule 7 alone (keep intervals lower than perfect fiths) is infringed in most of the combinations. There are only 5 combinations remaining:

```js
[
    ["C", "E", "G", "B"], // default
    ["E", "G", "B", "C"], // inversion 1
    ["G", "B", "C", "E"], // inversion 2
    ["B", "C", "E", "G"], // inversion 3
    ["B", "E", "G", "C"], // quartal voicing
]
```

Inversion 1 also violates rule 5 (play 3rd or 4th between two highest) and inversion 3 violates rule 3 (avoid low intervals at the bottom) giving:

```js
[
    ["C", "E", "G", "B"], // default
    ["G", "B", "C", "E"], // inversion 2
    ["B", "E", "G", "C"], // quartal voicing
]
```

### Problem

Bruteforcing all combinations and sorting out the bad ones would work but the algorithm would be very expensive, especially when using more notes.

### Custom Combination Algorithm

Instead of just generating all combinations, the bad ones could be avoided at the time of generation by stopping the recursion as soon as the rules are violated.
The following algorithm is similar to permutateArray, but with a validate function param added:

```js
export function permutateElements(array, validate?, path = []) {
    const isValid = (next) => !validate || validate(path, next, array);
    if (array.length === 1) {
        return isValid(array[0]) ? array : []
    }
    return array.filter(isValid).reduce((combinations, el) => [
        ...combinations,
        ...permutateElements(
            array.filter(e => e !== el),
            validate,
            path.concat([el])
        ).map(subcombinations => [
            el,
            ...subcombinations
        ])
    ], []);
}
```

This algorithm will be called on all elements that could be combined with the current tree. So we can avoid generating all combinations of a subtree that isnt even valid in the firstplace. A validation method for rule 7 could look like this:

```js
    // returns false for paths that would pick next notes that are more than a fifth away
    function rule7(path, next) {
            if (!path.length) { return true } // no notes picked yet
            const interval = Distance.interval(path[path.length - 1], next);
            return Interval.semitones(interval) < 6; // less than fifth
    }
    expect(permutateElements(["C", "E", "G", "B"], rule7)).toEqual(
        [["C", "E", "G", "B"],
        ["E", "G", "B", "C"],
        ["G", "B", "C", "E"],
        ["B", "C", "E", "G"],
        ["B", "E", "G", "C"]]
    );
```

The validation could now be wrapped to be combinable with more validation rules:

```js
    // returns function that validates the next interval with the given method
    function validateInterval(validate) {
        return (path, next, array) => {
            if (!path.length) { return true }
            const interval = Distance.interval(path[path.length - 1], next);
            return validate(interval);
        }
    }
    function validate(path, next, array) {
        return validateInterval(interval => Interval.semitones(interval) <= 6)(path, next, array);
    }

    expect(permutateElements(["C", "E", "G", "B"], validate)).toEqual(
        [["C", "E", "G", "B"],
         ["E", "G", "B", "C"],
         ["G", "B", "C", "E"],
         ["B", "C", "E", "G"],
         ["B", "E", "G", "C"]]
    );
```

.. adding rule 5 and 3 + combineValidators Method + combineValidators sugar:

```js
    // accepts validators as arguments and combines their results with logical and. Returns validator function.
    function combineValidators(...validators: ((path, next, array) => boolean)[]) {
        return (path, next, array) => validators
            .reduce((result, validator) => result && validator(path, next, array), true);
    }
    // returns validator that validates rules 7 3 and 5 of the generic interval rules
    function voicingValidator(path, next, array) {
        return combineValidators(
            validateInterval(interval => Interval.semitones(interval) <= 6),
            validateInterval((interval, { array }) => array.length !== 1 || Interval.semitones(interval) > 2),
            validateInterval((interval, { array }) => path.length !== 1 || Interval.semitones(interval) > 2)
        )(path, next, array);
    }
    expect(permutateElements(["C", "E", "G", "B"], voicingValidator)).toEqual(
        [["C", "E", "G", "B"], ["G", "B", "C", "E"], ["B", "E", "G", "C"]]
    );
```

### Wrapping up

For more sugar, lets add a new method to always get valid voicings for a given set of notes:

```js
export function getVoicingCombinations(notes, validator = (path, next, array) => true) {
    return permutateElements(notes, combineValidators(validator, voicingValidator));
}
```

### Complexity

Let's analyse the complexity of the algorithm:

```js
export function permutationComplexity(array, validate?, path = []) {
    let validations = 0;
    permutateElements(array, (path, next, array) => {
        ++validations;
        return !validate || validate(path, next, array)
    }, path);
    return validations;
}
```

This method adds a validator that counts up a number for each call. This number is equal to the number of recursive function calls.

```js
test('permutationComplexity', () => {
    expect(permutationComplexity([])).toBe(0);
    expect(permutationComplexity([1])).toBe(1);
    expect(permutationComplexity([1, 2])).toBe(4);
    expect(permutationComplexity([1, 2, 3])).toBe(15);
    expect(permutationComplexity([1, 2, 3, 4])).toBe(64);
    expect(permutationComplexity([1, 2, 3, 4, 5])).toBe(325);
    expect(permutationComplexity([1, 2, 3, 4, 5, 6])).toBe(1956);
    expect(permutationComplexity([1, 2, 3, 4, 5, 6, 7])).toBe(13699);
    // same goes for other element types:
    expect(permutationComplexity(['C', 'Eb', 'G', 'Bb'])).toBe(64);
    expect(permutationComplexity(['C', 'Eb', 'G', 'Bb', 'D'])).toBe(325);
    expect(permutationComplexity(['C', 'D', 'E', 'F', 'G', 'A', 'B'])).toBe(13699);
});
```

The complexity seems to follow this pattern:

```sh
c(n) = c(n-1) * n + n
```

### With interval validation

```js
    expect(permutationComplexity(['C', 'E', 'G'], voicingValidator)).toBe(12);
    expect(permutationComplexity(['C', 'C#', 'D', 'D#', 'E', 'F', 'F#'], voicingValidator)).toBe(372);
    expect(permutationComplexity(['C', 'D', 'E', 'F', 'G', 'A', 'B'], voicingValidator)).toBe(1187);
    expect(permutationComplexity(['C', 'Eb', 'Gb', 'A'], voicingValidator)).toBe(44);
    expect(permutationComplexity(['C', 'D', 'F', 'G'], voicingValidator)).toBe(29);
    expect(permutationComplexity(['C', 'Eb', 'G', 'Bb'], voicingValidator)).toBe(33);
    expect(permutationComplexity(['C', 'E', 'G', 'B', 'D'], voicingValidator)).toBe(86);
    expect(permutationComplexity(['C', 'D', 'E', 'F'], voicingValidator)).toBe(23);
```

Adding custom voicing validation, the complexity depends on the interval structure of the input.
But roughly said, the call counts are now reduced by 92%-98% on the upper limit, and 51% for four voices.

## Voice Leading

A very important part of playing sequential chords is voice leading. Good voice leading generally means as little movement as possible (but as much as necessary). Now that we know all valid combinations of pitch classes for a given chord, we need a way of selecting the best combinations based on the voicing that was played before.

The following method calculates the intervals between each chord note:

```js
export function voicingIntervals(chordA, chordB, min = true) {
    const intervals = chordA.map((n, i) => Distance.interval(n, chordB[i]));
    if (min) {
        return intervals.map(i => minInterval(i));
    }
    return intervals;
}
expect(util.voicingIntervals(['C', 'E', 'G'], ['C', 'Eb', 'G'])).toEqual(['1P', '-1A', '1P']);
expect(util.voicingIntervals(['C', 'E', 'G'], ['C', 'Eb', 'G'], false)).toEqual(['1P', '8d', '1P']);
expect(util.voicingIntervals(['C', 'E', 'G'], ['C', 'Eb', 'G', 'Bb'])).toEqual(['1P', '-1A', '1P']);
expect(util.voicingIntervals(['C', 'E', 'G', 'B'], ['C', 'Eb', 'G'])).toEqual(['1P', '-1A', '1P', null]);
```

There are some edge cases:

1. if chordB has more notes than chordA, The upper notes of chordB will be ignored.
2. if chordA has more notes than chordB, the upper intervals will be null

We will handle those cases later.

### Comparing interval groups

To be able to compare different voicing intervals, we need a numerical value that tells how much has changed:

```js
// adds semitones of intervals
export function semitoneMovement(intervals) {
    return intervals.reduce((semitones, interval) => {
        return semitones + Interval.semitones(interval)
    }, 0);
}
// adds absolute semitones of intervals
export function semitoneDifference(intervals) {
    return intervals.reduce((semitones, interval) => {
        return semitones + Math.abs(Interval.semitones(interval))
    }, 0);
}
```

The semitoneMovement method tells in which direction the whole movements tends. If for example one voice is going up and the other is going down the same amount, it will return 0.
The semitoneDifference method tells how much difference the intervals have in absolute semitones.
Now we can combine the voicingIntervals and semitone functions:

```js
export function voicingDifference(chordA, chordB, min = true) {
    return semitoneDifference(voicingIntervals(chordA, chordB, min));
}

export function voicingMovement(chordA, chordB, min = true) {
    return semitoneMovement(voicingIntervals(chordA, chordB, min));
}
```

Some test values:

```js
test('voicingDifference', () => {
    expect(util.voicingDifference(['C', 'E', 'G'], ['C', 'Eb', 'G'])).toBe(1);
    expect(util.voicingDifference(['C', 'E', 'G'], ['D', 'F#', 'A'])).toBe(6);
    expect(util.voicingDifference(['C', 'E', 'G'], ['E', 'G#', 'B'])).toBe(12);
});

test('voicingMovement', () => {
    expect(util.voicingMovement(['C', 'E', 'G'], ['C', 'Eb', 'G'])).toBe(-1);
    expect(util.voicingMovement(['C', 'E', 'G'], ['D', 'F#', 'A'])).toBe(6);
    expect(util.voicingMovement(['C', 'E', 'G'], ['B', 'E', 'G#'])).toBe(0);
});
```

### Finding the best combination

Now we can finally find out which voicing is the best combination to follow an existing combination:

```js
// finds best combination following the given notes, based on minimal movement
export function bestCombination(notes, combinations) {
    return combinations.reduce((best, current) => {
        const currentMovement = voicingDifference(notes, current);
        const bestMovement = voicingDifference(notes, best);
        if (Math.abs(currentMovement) < Math.abs(bestMovement)) {
            return current;
        }
        return best;
    })
}

test.only('bestCombination', () => {
    const dmin = [
        ['F', 'A', 'C', 'E'],
        ['C', 'E', 'F', 'A'],
        ['E', 'A', 'C', 'F']
    ];
    const g7 = [
        ['B', 'D', 'F', 'A'],
        ['B', 'F', 'A', 'D'],
        ['F', 'A', 'B', 'D'],
        ['A', 'D', 'F', 'B']
    ]
    expect(getVoicingCombinations(['F', 'A', 'C', 'E'])).toEqual(dmin);
    expect(getVoicingCombinations(['B', 'D', 'F', 'A'])).toEqual(g7);
    expect(bestCombination(dmin[0], g7)).toEqual(['F', 'A', 'B', 'D']);
    expect(bestCombination(dmin[1], g7)).toEqual(['B', 'D', 'F', 'A']);
    expect(bestCombination(dmin[2], g7)).toEqual(['F', 'A', 'B', 'D']);
});
```

Now we now the best voice leading from one voicing to the next!

## Adding Octaves

All notes that were handled so far were just relative pitch classes without an octave.
The following function will handle that:

```js
function getNextVoicing(chord, lastVoicing, bottomOctave = 3) {
    // make sure tonal can read the chord
    chord = getTonalChord(chord);
    // get chord notes
    const notes = Chord.notes(chord);
    // find voicings
    const combinations = getVoicingCombinations(notes);
    if(!lastVoicing) {
        return renderAbsoluteNotes(randomElement(combinations), bottomOctave);
    }
    // get pitch classes of last voicing
    const lastPitches = lastVoicing.map(n => Note.pc(n));
    // find best next combination
    const nextPitches =  bestCombination(lastPitches, combinations);
    // get nearest first note
    const nearest = getNearestNote(lastPitches[0], nextPitches[0]);
    bottomOctave = Note.props(nearest).oct;
    // render all notes, starting from the bottomOctave
    return renderAbsoluteNotes(notes, bottomOctave);
}
```

## Problems

When using the algorithm in the real world, one major problem is range:

```js
test.only('getNextVoicing', () => {
    let voicing;
    const startOctave = 3;
    let times = 3;
    for (let i = 0; i < times; ++i) {
        Note.names(' ').concat(['C']).forEach(note => {
            voicing = getNextVoicing(note + '-7', voicing, startOctave);
        });
    }
    expect(Note.oct(voicing[0])).toBe(startOctave + times);
});
```

This snippet will generate voicings that increase in seconds. The best voice leading for seconds
will always keep the existing structure. This means that the overall pitch will increase each time and eventually exhaust the range of the instrument. A real pianist will always stay in the range where the chords sound good, even if the jumps do not follow the best voice leading. So the algorithm needs a mechanism to force leading the voices in a certain direction. The direction could be implemented at.

## Available and Unavailable Tensions

https://www.youtube.com/watch?v=KKk1HLsbi7A

Available Tensions:
In a chord, you can always play a major second above a chord note (of its not the b7..)
All the other notes are either chord notes or unavailable tensions.

## Chord Symbols

https://www.youtube.com/watch?v=A6Ete9i5yyc

- always play 3 and 7
- always play highest note of chord symbol
- e.g. C^13 => play E B and A

## ireal voicings

InApp:

5
2
add9
+
o
ø
sus
△ ^
- m
△7 ^7
-7 m7
7
7sus
ø7
o7
△9 ^9
△13 ^13
6
6/9 69
^7#11

^9#11
^7#5
m6
m69
-△7 m^7
-△9 m^9
-9 m9
-11 m11
-7b5 m7b5
ø9
-b6 mb6
-#5 m#5
9
7b9
7#9
7#11
7b5
7#5
9#11
9b5

9#5
7b13
7#9#5
7#9b5
7#9#11
7b9#11
7b9b5
7b9#5
7b9#9
7b9b13
7alt
13
13#11
13b9
13#9
7b9sus
7susadd3
9sus
13sus
7b13sus

11


not used

add9
ø9
7alt
7susadd3

used in 1350 standards:


5
2
+
o
ø (h)
sus
△ ^
- m
△7 ^7
-7 m7
7
7sus
ø7
o7
△9 ^9
△13 ^13
6
6/9 69
^7#11
^9#11
^7#5
m6 -6
m69
-△7 m^7 -^7
-△9 m^9 -^9
-9 m9
-11 m11
-7b5 m7b5
-b6 mb6
-#5 m#5
9
7b9
7#9
7#11
7b5
7#5
9#11
9b5
9#5
7b13
7#9#5
7#9b5
7#9#11
7b9#11
7b9b5
7b9#5
7b9#9
7b9b13
13
13#11
13b9
13#9
7b9sus
9sus
13sus
7b13sus
11


sonderzeichen:

"W" > keine note über x (z.B W/C)
"r" > faulenzer


## Test

```
|  C-^9     |  C2       |  Ch       |  C9b5     |
|  C-#5     |  C7+      |  C        |  C^7      |
|  C7       |  C-7      |  Ch7      |  C7#9     |
|  C7b9     |  C^7#5    |  C^       |  C6       |
|  C9       |  C-6      |  Co7      |  C-^7     |
|  Co       |  C^9      |  C7#11    |  C7#5     |
|  C-       |  C7sus    |  C7sus4   |  C69      |
|  C7b13    |  C^       |  C+       |  C7b9b5   |
|  C-9      |  C9sus    |  C7b9sus  |  C7b9#5   |
|  C13      |  C^7#11   |  C-7b5    |  C^13     |
|  C7#9b5   |  C-11     |  C11      |  C7b5     |
|  C9#5     |  C13b9    |  C9#11    |  C13#11   |
|  C-b6     |  C7#9#5   |  C-69     |  C13sus   |
|  C^9#11   |  C7b9#9   |  Csus     |  C7#9#11  |
|  C7b9b13  |  C7b9#11  |  C13#9    |
```