hint
**hint is Humdrum's harmonic-interval
representation: a diatonic
interval size with its quality (M3, P5, m10, …). It can also be generated
with humlib's fb
tool via its
--hint option. Unlike fb's own default output, which reduces the whole
texture to intervals above the bass, hint is computed per pair of voices:
one spine for bass/tenor, one for bass/alto, one for tenor/soprano, and so on.
hint-<pair>
chorale-search generates one **hint-<pair> spine for every unordered pair of
the four voices: hint-12, hint-13, hint-14, hint-23, hint-24,
hint-34. Like fb, each of these is a single spine per chorale, not one per
voice, so a lookup against hint-14 always resolves to the same spine
regardless of which voices you searched for. Searching hint-14 with
"voices": "tenor" reads the exact same bass/soprano data as "voices": "bass".
There's no bare **hint feature (unlike fb, which does exist as its own
single spine derived the same way): every hint spine is tied to a specific pair,
so feature: "hint" or a bare "hint" key always matches nothing.
Token format
A **hint token is a single interval: an optional quality letter (M, m,
P, A, d, …) followed by a diatonic number, e.g. m3 or P5.
The interval is always given as an absolute value, measured from the lower-numbered voice of the pair up to the higher-numbered voice. It's never negative, so the interval size alone can't tell you whether the lower-numbered voice actually sounds below the other at that moment, only how far apart they are.
Just like fb, the quality letter can be omitted to match any quality:
| Pattern value | Matches figure 3 as |
|---|---|
"M3" | only a major 3rd |
"3" | any 3rd, any quality |
A widely spaced pair like bass/soprano routinely produces genuinely compound
intervals (M10, P12, M17, and so on) rather than folding them down to
M3/P5/M3 within an octave. See
hintReduceCompound if you want a pattern
value like "3" to also match a 10, 17, etc.
{
"feature": "hint-14",
"voices": "bass",
"pattern": [
{ "hint-14": "P8", "fermata": true }
]
}
finds every moment the bass carries a fermata while it's exactly an octave apart from the soprano.
hint-<voice>
A pattern key can also name a pair relative to whichever voice is currently
being walked, e.g. hint-2. Searching voices: "1234" with a hint-2
constraint resolves the pair separately for each voice being walked: hint-12
while walking the bass, hint-23 while walking the alto, hint-24 while
walking the soprano.
{
"feature": "kern",
"voices": "1234",
"pattern": [
{ "hint-2": "P8", "fermata": true }
]
}
finds the fermatas where a voice is an octave above or below the tenor.
hint-<voice> only makes sense as a cross-referenced constraint next to another
driving feature (kern, deg, …), since there's no hint-2 spine to walk
directly, it's resolved fresh at each onset, relative to whichever voice is
being searched.
hint-<voice> is what makes a genuine parallel-motion search possible: both
sides of the pair stay fixed to the same two voices across every position in the
pattern, because one side is the digit you wrote and the other is whichever
voice the search is walking, neither changes from position to position.
{
"feature": "kern",
"voices": "alto",
"pattern": [
{ "hint-2": "P5" },
{ "hint-2": "P5" }
]
}
finds consecutive perfect 5ths between the alto and the tenor specifically, not "any voice a 5th above any other voice twice in a row", which a pair wildcard can't express, since it lets the pair itself vary from one position to the next.
Comparing interval sizes
The size of the interval can be compared with a
comparison, in hint-<pair>, hint-<voice> and wildcard pairs
alike. The value is a diatonic number ("10": the number alone is compared, so every
interval of the same number is equally wide) or a number with a quality ("M10": the
size in semitones is compared).
{
"feature": "hint-14",
"voices": "bass",
"pattern": [
{ "hint-14": { "operator": "gt", "value": "22" } }
]
}
finds the moments the outer voices are more than three octaves apart (a 22nd). The
size is the one in the score, so hintReduceCompound
does not fold it into the octave first. A tenth is a 10, which is what tells it from a
third.
Wildcard pairs
Either digit (or both) in a hint-<pair> key can be *, meaning "any pair
matching this digit pattern". hint-*4 means "hint-14, hint-24, or hint-34: any
voice's interval to the soprano". The position is satisfied if any one of
the matching pairs currently has the pattern value, not all of them at once:
{
"feature": "kern",
"pattern": [
{ "hint-*4": "M7" }
]
}
finds every onset where at least one lower voice forms a major 7th with the
soprano, regardless of which voice it is. Unlike hint-<voice>, a wildcard pair
is re-evaluated independently at each position, so it can't pin down "the same
two voices" across a multi-position pattern the way hint-<voice> does.
Searching several pairs at once
A query can be driven by a set of voice pairs instead of one pair: hint-**
(every pair), or a set with a voice in its place, like hint-*4 (the soprano above
another voice: 14, 24 and 34) or hint-1* (the bass below another voice: 12, 13
and 14), see Wildcard pairs. A set needs at least one pair, so
hint-4* (the soprano is never the lower voice) can't drive a query. The search
runs once for each pair of the set, and every result has the pair it is of as its
feature, e.g. hint-24.
Inside such a query:
hint-@pairin the pattern is the interval of the pair being searched, so every position is about the same two voices. As with every key, a leading!negates the position:{ "!hint-@pair": "P5" }holds where that pair is not a fifth.hint-@pairand a pair of the set, likehint-24, can't be keys of the same position: while the pair 24 is searched, both would be the keyhint-24;- every other
hintkey keeps its usual meaning. A set likehint-**orhint-*4in the pattern holds if any pair of the set has the value, not only the pair being searched, see Wildcard pairs; @lowerand@upperinvoices, in the query and insimultaneousWith, are the lower and the upper voice of that pair. The query's ownvoicesis all voices (the default), which reads each pair once, or@lowerand@upper.
For a complete query, see Parallel fifths downwards between any two voices.
Using it in a pattern
hint-<pair> is most useful either as the driving feature (walking that
specific pair's interval as it changes) or as a secondary constraint alongside
kern/deg/mint (checking "what's this specific pair of voices doing when
that melodic thing happens"); hint-<voice> is a secondary constraint only.
{
"feature": "deg",
"voices": "soprano",
"pattern": [
{ "deg": "2" },
{ "deg": "1", "hint-14": "P8" }
]
}
finds a soprano 2-to-1 resolution where the tonic lands exactly an octave above
the bass. See Patterns for OR-lists, wildcards, multi-feature
positions, and negation, all of which work the same way for hint keys as for
any other feature.