-
-
Notifications
You must be signed in to change notification settings - Fork 113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stateless voicings + tonleiter lib #647
Conversation
added another voicing feature: offset("0 <[2 1] 2>")
.chord("<Dm7 G7 C^7 A7b9>")
.anchor("E4")
.voicing()
.piano()
|
+ simplify voicing logic
and another feature: when n(run(12))
.chord("<Dm7 G7 C^7 A7b9>")
.voicing() I am already having a blast using these new functions and I cannot wait to finish them. |
I am still wondering if the voice dictionary (argument to voicing function) should also be a control.. Also, another thought: related to #223 the voicing function could also accept an object with all the controls in it, like voicing({
n: run(12),
chord: "<Dm7 G7 C^7 A7b9>",
dict: "lefthand"
}) edit: also there should probably be a default dictionary which understands a broad selection of chords and returns the most common voicings |
voicing-scales.mp4 |
- standalone voicing function - simplify voicing control names
voicing(
n(run(4)) // plays voicing like a scale
.chord("<Dm7 G7 C^7 A7b9>") // which chord to play
.dict("steps") // or dictionary
.anchor("B5") // former called voiceMax / voiceBelow
.add.squeeze(offset("0,3 1 2")) // how much to shift the voicing up or down
.mode('max') // if set to below, the anchor note will be filtered out (for "melody ducking")
).piano() alternatively, the above can also be written as: n(run(4)) // plays voicing like a scale
.chord("<Dm7 G7 C^7 A7b9>") // which chord to play
.dict("steps") // or dictionary
.anchor("B5") // former called voiceMax / voiceBelow
.add.squeeze(offset("0,3 1 2")) // how much to shift the voicing up or down
.mode('max') // if set to below, the anchor note will be filtered out (for "melody ducking")
.voicing().piano() so the new control names are:
i guess it's not important to namespace the controls for voicings, as they could be reused in another context (similar to |
+ rename voiceBelow to renderVoicing
+ pull logic in from voicings function
+ pull out static objects
+ add registerVoicings for the new logic
this is now ready to merge. @yaxu ok with the naming of the new controls: https://github.com/tidalcycles/strudel/pull/647/files#diff-b1da86c00bc85a5a5848acac010d999cdfd66a9f97b9f107b09f70fa519c3b51R576 ?
|
+ detect chord obj in rootNotes
Sorry for being slow! Are these standard names in the world of harmony? I can't see them being used here, but I don't really know anything about voicing. https://en.wikipedia.org/wiki/Voicing_(music)
Are you keen on Overall no objections if you think these are the best names. |
nope, only
Not specifically keen on it. But even if there was a naming collision, it would not be a problem, as n("0 1 2 3").chord("Cm").voicing().s("gm_epiano1")
// alternative syntax:
voicing(
n("0 1 2 3").chord("Cm")
).s("gm_epiano1") In the above example, |
I've now added a more in depth description of all the new functions at the top of this PR |
Ah nice! Sorry I hadn't looked into the details of it, the scoping is nice ! |
fixes #506
implements a new algorithm for voicing chords
examples:
new functions:
voicing
voicing
is the only function that is not a control, but rather a function that consumes all the voicing related controls and renders them into actual notes. It accepts either strings or objects. Strings are interpreted as chords. Examples:chord
chord
s are just strings where the beginning is expected to be a valid pitch class (C, C#, Db, ... ) and the rest is considered to be the chord symbol (can also be empty, which is normally the case for major chords).dictionary / dict
dictionary
or shortdict
defines how chord symbols are turned into individual notes, or in other words, how they are "voiced".You can either pass a string or a dictionary:
If
dict
is not set, the default dictionarydefaultDictionary
is used, which understands the most common chord symbols (currently just triads and sevenths chords, but can be extended in the future).In the dictionary, the numbers are semitones relative to the root note, so
['0 4 7', '4 7 12', '7 12 16']
inC
would be['C E G', 'E G C', 'G C E']
. These pitches have no octaves, so each voicing can be played in any octave.anchor
To decide which voicing to actually play for a certain chord, the
anchor
control is used.It expects a single note to align the voicing to. It falls back to
E5
.With the above dictionary and the default anchor, a C chord will always be 'G4 C5 E5', using the '7 12 16' option, because that voicing's top note is closest to
E5
.The anchor is the actual "trick" to get voice leading without state, as a voicing does not need to know which voicing came last (which was the case with the old voicing algorithm).
mode
The behavior of
anchor
is not fixed to always align the voicing to the top note. Instead, themode
control can be used to change that alignment to:offset
The
offset
control applies an offset to the selected voicing. For example:... the resulting voicing would be
G4 C5 E5
, which is the voicing with index 2 in the dictionary.If we apply
.offset(1)
, the selected voicing index will be 2+1 = 3. Because there is no voicing with index 3, we wrap around to index 0, landing on0 3 7
, givingC5 E5 G5
. So with this particular set of voicingsoffset
controls the inversions, but that term would not apply for sets of voicings that do not include every rotation.The above explanation sounds complicated, but when you use it, it makes much more sense..
n
The
n
control selects an index out of the rendered voicing, which allows to play the voicing like a scale:is equal to
Note that
n
= 3 wraps around to the first note of the voicing, but 1 octave higher.edit: updated this whole post after the api changed during the development of this PR. Posts further down might still reference or iterate on the old version of this post.. The above functions are the actual up to date information