| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Harmonic.Framework.Builder.Strata
Description
Synopsis
- adjacentInTristrata :: Tristrata -> StrataLabel -> [StrataLabel]
- allowedNext :: [Tristrata] -> (StrataLabel, Tristrata) -> [(StrataLabel, Tristrata)]
- initialPlacement :: [Tristrata] -> StrataLabel -> (StrataLabel, Tristrata)
- modeForTriad :: [(StrataLabel, Tristrata)] -> Int -> Int -> ModeResult
- pickPartner :: [(StrataLabel, Tristrata)] -> Int -> StrataLabel -> Tristrata -> StrataLabel
- positionalPartner :: Tristrata -> StrataLabel -> StrataLabel
- selectNext :: (StrataLabel, Tristrata) -> [(StrataLabel, Tristrata)] -> Maybe (StrataLabel, Tristrata)
- selectNextSeeded :: Int -> (StrataLabel, Tristrata) -> [(StrataLabel, Tristrata)] -> Maybe (StrataLabel, Tristrata)
Documentation
adjacentInTristrata :: Tristrata -> StrataLabel -> [StrataLabel] Source #
In-tristrata circular neighbourhood of a strata: positions {p-1, p, p+1}
mod 3 in the tristrata t. The current strata is included so a bar may
repeat the previous strata within the same tristrata.
allowedNext :: [Tristrata] -> (StrataLabel, Tristrata) -> [(StrataLabel, Tristrata)] Source #
Complete viable (strata', tristrata') candidate set for a given
(strata, tristrata) step, respecting the allowed-tristrata allow-list.
For every (t', p') in where tristrataOf st' is allowed, emit every
(s', t') with s' drawn from .adjacentInTristrata t' s
initialPlacement :: [Tristrata] -> StrataLabel -> (StrataLabel, Tristrata) Source #
Initial (strata, tristrata) placement: use the supplied starting strata,
and pick the lowest-dissonance allowed tristrata that contains it. If no
allowed tristrata contains the strata, fall back to the first allowed one
(edge case — caller should usually avoid this via a sensible default).
Arguments
| :: [(StrataLabel, Tristrata)] | |
| -> Int | |
| -> Int | triad's harmonic root PC (0..11) |
| -> ModeResult |
Triad-anchored, history-aware mode selector for bar i.
Walks barSeq backward from i-1 to find the most recent strata
≠ barSeq[i].strata; if none, uses positionalPartner on
barSeq[i].tristrata. Unions strataChroma sCurr with the partner's
chroma, then classifies via classifyModeAt pinned to triadRootPC.
Returns ModeOk for a normal classification; ModeInvalid when the
union doesn't have exactly 7 unique pitch classes (only reachable via
absStrata overrides that violate tristrata adjacency). When the
7-PC union doesn't classify under any of the 28 mode patterns pinned
to triadRootPC, returns ModeOk (Mode Aeolian (P triadRootPC)) as
a benign fallback.
Arguments
| :: [(StrataLabel, Tristrata)] | full bar sequence (0-indexed) |
| -> Int | current bar index |
| -> StrataLabel | current strata |
| -> Tristrata | current tristrata (used for fallback) |
| -> StrataLabel |
Choose a partner strata for the union construction at bar i.
Preference order:
- The most recent prior bar whose strata
≠ s_curr— "last different" (preserves the user's intended behaviour for mid-run bars where the mode reflects the incoming transition). - If no different prior bar exists (bar 0, or the entire history
so far shares
s_curr), look forward for the first future bar whose strata≠ s_curr— the "firstnextdifferent" rule. This lets bar 0's mode reflect the outgoing transition to the next distinct strata, which is musically more informative than the positional fallback. - Otherwise (single-strata run), fall back to
positionalPartnerinside the current bar's tristrata.
positionalPartner :: Tristrata -> StrataLabel -> StrataLabel Source #
Bar-0 / no-prior starter rule: pick a fixed partner strata inside the given tristrata based on the current strata's position.
- pos 1 → ts2
- pos 2 → ts1
- pos 3 → ts1
Yields a 7-PC pair-union (which is what the framework guarantees inside a single tristrata).
selectNext :: (StrataLabel, Tristrata) -> [(StrataLabel, Tristrata)] -> Maybe (StrataLabel, Tristrata) Source #
Select the next (s', t') from a candidate pool using the tie-break rule:
- Prefer
s' == s_{prev}(strata continuity); within that, prefert' == t_{prev}if still valid, otherwise lowest-dissonance tristrata. - Prefer
t' == t_{prev}(tristrata continuity) — lowest-dissonance option inside the previous tristrata wins over a more-consonant strata in another tristrata. - Otherwise pick by
(.strataDissonances',tristrataDissonancet')
Returns Nothing on empty pool.
Arguments
| :: Int | rng sample (any Int) |
| -> (StrataLabel, Tristrata) | prior bar |
| -> [(StrataLabel, Tristrata)] | candidate pool |
| -> Maybe (StrataLabel, Tristrata) |
Seeded stochastic variant of selectNext. Permits the walk to
actually traverse — the categorical same-strata-first rule of
selectNext locks the walk to its starting strata indefinitely,
which is musically sterile.
Given an Int sample drawn from an RNG by the caller, this picks a
candidate from pool with the following preference order:
- Prefer candidates whose strata
≠ sPrev(forces exploration). Among those, prefer ones sharingtPrev(tristrata continuity) over those in other tristrata. - Fall back to the self-loop only when the pool contains nothing
else (rare — happens under extreme
hcTristrata/relStratanarrowing).
Within the preferred group, the sample index (mod group size) picks
the concrete candidate. This gives run-to-run variety while
respecting genPs continuity intent (staying inside the current
tristrata's harmonic region when possible).