From e38811d325a76d8885aa3720e40e1ceb41c52784 Mon Sep 17 00:00:00 2001 From: eefano <77832+eefano@users.noreply.github.com> Date: Mon, 8 Jun 2026 21:09:23 +0200 Subject: [PATCH] oldabove and oldroot, documentation --- packages/core/controls.mjs | 11 +++++++++-- packages/tonal/tonleiter.mjs | 6 +++++- packages/tonal/voicings.mjs | 3 +++ website/src/pages/understand/voicings.mdx | 5 ++++- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 8f733c321..d4e05393c 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -2352,11 +2352,18 @@ export const { offset } = registerControl('offset'); **/ export const { octaves } = registerControl('octaves'); /** - * Remove anchor note from the voicing. Useful for melody harmonization + * How the voicing is aligned to the anchor + * - `below`: top note <= anchor + * - `duck`: top note <= anchor, anchor excluded + * - `above`: bottom note >= anchor + * - `root`: bottom note is the lowest root of the chord >= anchor + * + * - `oldabove` : old (buggy) behavior of above, kept for legacy reason + * - `oldroot` : old (buggy) behavior of root, kept for legacy reason * * @name mode * @tags tonal - * @param {string | Pattern} modeName one of {below | above | duck | root} + * @param {string | Pattern} modeName one of {below | above | duck | root | oldabove | oldroot} * @example * mode("").chord("C").voicing() * diff --git a/packages/tonal/tonleiter.mjs b/packages/tonal/tonleiter.mjs index 5306317f6..41f5e7c7d 100644 --- a/packages/tonal/tonleiter.mjs +++ b/packages/tonal/tonleiter.mjs @@ -134,12 +134,16 @@ let modeTarget = { duck: (v) => v.slice(-1)[0], above: (v) => v[0], root: (v) => v[0], + oldabove: (v) => v[0], + oldroot: (v) => v[0], }; let modeMult = { below: 1, duck: 1, above: -1, root: -1, + oldabove: 1, + oldroot: 1, }; export function renderVoicing({ chord, dictionary, offset = 0, n, mode = 'below', anchor = 'c5', octaves = 1 }) { @@ -163,7 +167,7 @@ export function renderVoicing({ chord, dictionary, offset = 0, n, mode = 'below' } return diff * mult; }); - if (mode === 'root') { + if (mode === 'root' || mode === 'oldroot') { bestIndex = 0; } diff --git a/packages/tonal/voicings.mjs b/packages/tonal/voicings.mjs index 7dcc6a77b..de0e2595a 100644 --- a/packages/tonal/voicings.mjs +++ b/packages/tonal/voicings.mjs @@ -185,6 +185,9 @@ export const rootNotes = register('rootNotes', function (octave, pat) { * - `below`: top note <= anchor * - `duck`: top note <= anchor, anchor excluded * - `above`: bottom note >= anchor + * - `root`: bottom note is the lowest root of the chord >= anchor + * - `oldabove` : old (buggy) behavior of above, kept for legacy reason + * - `oldroot` : old (buggy) behavior of root, kept for legacy reason * - `offset`: whole number that shifts the voicing up or down to the next voicing * - `n`: if set, the voicing is played like a scale. Overshooting numbers will be octaved * diff --git a/website/src/pages/understand/voicings.mdx b/website/src/pages/understand/voicings.mdx index 7d9c13d90..8711f0637 100644 --- a/website/src/pages/understand/voicings.mdx +++ b/website/src/pages/understand/voicings.mdx @@ -287,7 +287,10 @@ The modes are: - `below`: the top note of the voicing is lower than or equal to the anchor (default) - `above`: the bottom note of the voicing is higher than or equal to the anchor - `duck`: the top note of the voicing is lower than the anchor -- `root`: the bottom note of the voicing is always the root note closest to the anchor +- `root`: the bottom note of the voicing is always the lowest root note higher than or equal to the anchor + +- `oldabove` : old (buggy) behavior of above, kept for legacy reasons +- `oldroot` : old (buggy) behavior of root, kept for legacy reasons The `anchor` can also be set from within the `mode` function: