mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-11 13:48:34 +00:00
add root mode for voicings
+ allow numbers as anchor
This commit is contained in:
parent
4d25e3b90b
commit
27049eb706
@ -60,12 +60,12 @@ export const step2semitones = (x) => {
|
|||||||
return Interval.semitones(x);
|
return Interval.semitones(x);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const x2midi = (x) => {
|
export const x2midi = (x, defaultOctave) => {
|
||||||
if (typeof x === 'number') {
|
if (typeof x === 'number') {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
if (typeof x === 'string') {
|
if (typeof x === 'string') {
|
||||||
return noteToMidi(x);
|
return noteToMidi(x, defaultOctave);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,13 +88,14 @@ let modeTarget = {
|
|||||||
below: (v) => v.slice(-1)[0],
|
below: (v) => v.slice(-1)[0],
|
||||||
duck: (v) => v.slice(-1)[0],
|
duck: (v) => v.slice(-1)[0],
|
||||||
above: (v) => v[0],
|
above: (v) => v[0],
|
||||||
|
root: (v) => v[0],
|
||||||
};
|
};
|
||||||
|
|
||||||
export function renderVoicing({ chord, dictionary, offset = 0, n, mode = 'below', anchor = 'c5', octaves = 1 }) {
|
export function renderVoicing({ chord, dictionary, offset = 0, n, mode = 'below', anchor = 'c5', octaves = 1 }) {
|
||||||
const [root, symbol] = tokenizeChord(chord);
|
const [root, symbol] = tokenizeChord(chord);
|
||||||
const rootChroma = pc2chroma(root);
|
const rootChroma = pc2chroma(root);
|
||||||
anchor = anchor?.note || anchor;
|
anchor = x2midi(anchor?.note || anchor, 4);
|
||||||
const anchorChroma = pitch2chroma(anchor);
|
const anchorChroma = midi2chroma(anchor);
|
||||||
const voicings = dictionary[symbol].map((voicing) =>
|
const voicings = dictionary[symbol].map((voicing) =>
|
||||||
(typeof voicing === 'string' ? voicing.split(' ') : voicing).map(step2semitones),
|
(typeof voicing === 'string' ? voicing.split(' ') : voicing).map(step2semitones),
|
||||||
);
|
);
|
||||||
@ -110,18 +111,21 @@ export function renderVoicing({ chord, dictionary, offset = 0, n, mode = 'below'
|
|||||||
}
|
}
|
||||||
return diff;
|
return diff;
|
||||||
});
|
});
|
||||||
|
if (mode === 'root') {
|
||||||
|
bestIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
const octDiff = Math.ceil(offset / voicings.length) * 12;
|
const octDiff = Math.ceil(offset / voicings.length) * 12;
|
||||||
const indexWithOffset = _mod(bestIndex + offset, voicings.length);
|
const indexWithOffset = _mod(bestIndex + offset, voicings.length);
|
||||||
const voicing = voicings[indexWithOffset];
|
const voicing = voicings[indexWithOffset];
|
||||||
const targetStep = modeTarget[mode](voicing);
|
const targetStep = modeTarget[mode](voicing);
|
||||||
const anchorMidi = noteToMidi(anchor, 4) - chromaDiffs[indexWithOffset] + octDiff;
|
const anchorMidi = anchor - chromaDiffs[indexWithOffset] + octDiff;
|
||||||
|
|
||||||
const voicingMidi = voicing.map((v) => anchorMidi - targetStep + v);
|
const voicingMidi = voicing.map((v) => anchorMidi - targetStep + v);
|
||||||
let notes = voicingMidi.map((n) => midi2note(n));
|
let notes = voicingMidi.map((n) => midi2note(n));
|
||||||
|
|
||||||
if (mode === 'duck') {
|
if (mode === 'duck') {
|
||||||
notes = notes.filter((_, i) => voicingMidi[i] !== noteToMidi(anchor));
|
notes = notes.filter((_, i) => voicingMidi[i] !== anchor);
|
||||||
}
|
}
|
||||||
if (n !== undefined) {
|
if (n !== undefined) {
|
||||||
return [scaleStep(notes, n, octaves)];
|
return [scaleStep(notes, n, octaves)];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user