| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Harmonic.Lib
Description
Overview
One import gives a performance script everything it needs: the generative engine, the music-theory primitives it reasons over, and the TidalCycles bridge that turns its output into sound.
import Harmonic.Lib
Quick start
Generation reads as a chain of modifiers applied to a generator. Each modifier narrows what the engine may choose; the generator at the end of the chain runs the walk:
tempo = 87
ctx = invSkip 1
$ hcOvertones "E A D G"
$ hcKey "2#"
$ hContext
start <- lead "C maj"
s <- seek "*" $ cue start $ tonal ctx $ len 8 $ entropy 0.4 $ attempt 3 12 $ gen
seek picks the corpus — "*" for all composers, "bach" for one,
"bach:30 debussy:70" for a weighted blend, "none" to run offline with
no Neo4j. attempt generates several candidates and keeps the best.
The result is then played by describing a form and handing it to instruments:
form = [ at 0 1.0 1.0 s ]
do
let k = iK tempo form (warp "[1 2 3 4]/4")
mapM_ id [ hush, setbpm tempo
, p "strings" $ stack
[ violin1 T (0,1) k voiceLines flow Soprano
, cello T (0,1) k voiceLines flow Tenor8vb
, contrabass T (0,1) k voiceLines grid Bass8vb
]
]
Verbosity
Every generator has three tiers, marked by the prime suffix — the same convention used throughout the library for tiers and variants:
gen— the chord grid onlygen'— per-step musical context and the gridgen''— full traces, the grid, and the multi-attempt scoreboard
The tiers have identical types, so switching verbosity never changes the
surrounding code. The same holds for genP / genP' / genP'',
genFrom / genFrom' / genFrom'', and the Roman numeral aliases.
Where to go next
- Harmonic.Framework.Builder — the generation engine and every modifier
- Harmonic.Interface.Tidal.Orchestra — the 15 orchestral instruments
- Harmonic.Interface.Tidal.Arranger — voicing strategies and rearranging
- Harmonic.Interface.Tidal.Form — form and kinetics
Legacy positional interface
Predating the modifier chain, genSilent, genStandard and genVerbose
take their arguments positionally and share one signature:
genSilent :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
They remain supported, but note that initCadenceState silently truncates
chords of more than three pitch classes to a triad; lead is the
better-behaved way to build a starting state.
Synopsis
- gen :: GenConfig
- gen' :: GenConfig
- gen'' :: GenConfig
- gen4 :: GenConfig
- gen4' :: GenConfig
- gen4'' :: GenConfig
- quad :: GenConfig -> GenConfig
- genGrid :: GenConfig
- genFrom :: ProgressionContext -> Int -> Int -> GenConfig
- genFrom' :: ProgressionContext -> Int -> Int -> GenConfig
- genFrom'' :: ProgressionContext -> Int -> Int -> GenConfig
- genP :: StrataLabel -> GenConfig
- genP' :: StrataLabel -> GenConfig
- genP'' :: StrataLabel -> GenConfig
- genI :: GenConfig
- genII :: GenConfig
- genIII :: GenConfig
- genIV :: GenConfig
- genV :: GenConfig
- genVI :: GenConfig
- genVII :: GenConfig
- genVIII :: GenConfig
- genIX :: GenConfig
- genX :: GenConfig
- genXI :: GenConfig
- genI' :: GenConfig
- genII' :: GenConfig
- genIII' :: GenConfig
- genIV' :: GenConfig
- genV' :: GenConfig
- genVI' :: GenConfig
- genVII' :: GenConfig
- genVIII' :: GenConfig
- genIX' :: GenConfig
- genX' :: GenConfig
- genXI' :: GenConfig
- genI'' :: GenConfig
- genII'' :: GenConfig
- genIII'' :: GenConfig
- genIV'' :: GenConfig
- genV'' :: GenConfig
- genVI'' :: GenConfig
- genVII'' :: GenConfig
- genVIII'' :: GenConfig
- genIX'' :: GenConfig
- genX'' :: GenConfig
- genXI'' :: GenConfig
- cue :: CadenceState -> GenConfig -> GenConfig
- len :: Int -> GenConfig -> GenConfig
- seek :: String -> GenConfig -> IO ProgressionContext
- entropy :: Double -> GenConfig -> GenConfig
- tonal :: HarmonicContext -> GenConfig -> GenConfig
- relStrata :: String -> GenConfig -> GenConfig
- absStrata :: String -> GenConfig -> GenConfig
- sameBoost :: Double -> GenConfig -> GenConfig
- flipBoost :: Double -> GenConfig -> GenConfig
- triBoost :: Double -> GenConfig -> GenConfig
- attempt :: Int -> Int -> GenConfig -> GenConfig
- viability :: Double -> GenConfig -> GenConfig
- data GenConfig = GenConfig {
- _gcCue :: IO CadenceState
- _gcLen :: Int
- _gcSeek :: String
- _gcEntropy :: Double
- _gcTonal :: HarmonicContext
- _gcVerbosity :: Verbosity
- _gcMode :: GenMode
- _gcLenOverride :: Maybe Int
- _gcRelStrata :: Maybe [Int]
- _gcAbsStrata :: Maybe [StrataLabel]
- _gcBoostSame :: Double
- _gcBoostFlip :: Double
- _gcBoostTri :: Double
- _gcQuad :: Bool
- _gcMaxAttempts :: Int
- _gcViableTarget :: Int
- _gcViabilityFloor :: Double
- data GenMode
- data Verbosity
- defaultGenConfig :: GenConfig
- execGenConfig :: GenConfig -> IO Progression
- execGenConfigPC :: GenConfig -> IO ProgressionContext
- genSilent :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
- genStandard :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
- genVerbose :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
- genPrint :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
- genPrint' :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
- genPrint'' :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
- data HarmonicContext = HarmonicContext {
- _hcOvertones :: Text
- _hcKey :: Text
- _hcRoots :: Text
- _hcDrift :: Drift
- _hcInversionSpacing :: Int
- _hcPedal :: Text
- _hcTristrata :: Text
- harmonicContext :: Text -> Text -> Text -> HarmonicContext
- hContext :: HarmonicContext
- data Drift
- hcOvertones :: String -> HarmonicContext -> HarmonicContext
- hcKey :: String -> HarmonicContext -> HarmonicContext
- hcRoots :: String -> HarmonicContext -> HarmonicContext
- dissonant :: HarmonicContext -> HarmonicContext
- consonant :: HarmonicContext -> HarmonicContext
- invSkip :: Int -> HarmonicContext -> HarmonicContext
- hcPedal :: String -> HarmonicContext -> HarmonicContext
- hcTristrata :: String -> HarmonicContext -> HarmonicContext
- data GeneratorConfig = GeneratorConfig {}
- defaultConfig :: GeneratorConfig
- module Harmonic.Rules.Types.Pitch
- module Harmonic.Rules.Types.Harmony
- module Harmonic.Evaluation.Scoring.Dissonance
- module Harmonic.Rules.Constraints.Overtone
- voiceLeadingCost :: [Int] -> [Int] -> Int
- totalCost :: [[Int]] -> Int
- cyclicCost :: [[Int]] -> Int
- voiceMovement :: Int -> Int -> Int
- minimalMovement :: PitchClass -> PitchClass -> Int
- allVoicings :: [Int] -> [[Int]]
- initialCompact :: Int -> [Int] -> [Int]
- solveRoot :: [[Int]] -> [[Int]]
- solveFlow :: [[Int]] -> [[Int]]
- module Harmonic.Rules.Types.Progression
- module Harmonic.Rules.Types.Scale
- module Harmonic.Rules.Types.ProgressionContext
- module Harmonic.Traversal.Probabilistic
- overtones :: String -> [PitchClass]
- key :: String -> [PitchClass]
- funds :: String -> [PitchClass]
- tuning :: String -> [PitchClass]
- wildcard :: String -> Bool
- parseOvertones :: Text -> [PitchClass]
- parseKey :: Text -> [PitchClass]
- parseFunds :: Text -> [PitchClass]
- parseTuning :: Text -> [PitchClass]
- isWildcard :: Text -> Bool
- parseTuningNamed :: Text -> [(String, Int)]
- module Harmonic.Evaluation.Database.Query
- connectNeo4j :: IO Pipe
- module Harmonic.Rules.Import.CSV
- module Harmonic.Rules.Import.Transform
- type VoiceFunction = Progression -> [[Int]]
- voiceRange :: (Int, Int) -> Pattern Int -> Pattern Int
- arrange :: (Double, Double) -> IK -> (Int, Int) -> Layer -> VoiceFunction -> (Progression -> Progression) -> [Pattern Int] -> Pattern ValueMap
- arrange' :: (Double, Double) -> IK -> (Int, Int) -> Layer -> VoiceFunction -> (Progression -> Progression) -> [Pattern Int] -> Pattern ValueMap
- parallel :: Pattern Note -> ControlPattern -> ControlPattern
- warp :: String -> Pattern Int
- rep :: ProgressionContext -> Pattern Time -> Pattern Int
- lookupChordAt :: Time -> Pattern Int -> Int
- lookupChord :: ProgressionContext -> Int -> Chord
- lookupProgression :: ProgressionContext -> Pattern Int -> Pattern [Int]
- overlapF :: Int -> Progression -> Progression
- data FormNode = FormNode {}
- data FormTime
- data Transition
- data Kinetics = Kinetics {}
- type IK = (Kinetics, Pattern Int)
- at :: Double -> Double -> Double -> ProgressionContext -> FormNode
- at' :: Double -> Double -> Double -> ProgressionContext -> FormNode
- rh :: Double -> Double -> Double -> ProgressionContext -> FormNode
- rh' :: Double -> Double -> Double -> ProgressionContext -> FormNode
- iK :: Double -> [FormNode] -> Pattern Int -> IK
- lK :: Pattern Double -> Pattern Double -> ProgressionContext -> Pattern Int -> IK
- formK :: Double -> [FormNode] -> Kinetics
- ki :: (Double, Double) -> IK -> Pattern a -> Pattern a
- slate :: (Double, Double) -> IK -> [Pattern a] -> Pattern a
- withForm :: IK -> (ProgressionContext -> Pattern ValueMap) -> Pattern ValueMap
- rotate :: Int -> ProgressionContext -> ProgressionContext
- excerpt :: Int -> Int -> ProgressionContext -> ProgressionContext
- insert :: CadenceState -> Int -> ProgressionContext -> ProgressionContext
- switch :: Int -> Int -> ProgressionContext -> ProgressionContext
- clone :: Int -> Int -> ProgressionContext -> ProgressionContext
- extract :: Int -> ProgressionContext -> CadenceState
- transposeP :: Int -> ProgressionContext -> ProgressionContext
- reverse :: ProgressionContext -> ProgressionContext
- fuse :: [ProgressionContext] -> ProgressionContext
- fuse2 :: ProgressionContext -> ProgressionContext -> ProgressionContext
- interleave :: ProgressionContext -> ProgressionContext -> ProgressionContext
- expandP :: Int -> ProgressionContext -> ProgressionContext
- progOverlap :: Int -> Progression -> Progression
- progOverlapF :: Int -> Progression -> Progression
- progOverlapB :: Int -> Progression -> Progression
- grid :: Progression -> [[Int]]
- flow :: Progression -> [[Int]]
- lite :: Progression -> [[Int]]
- literal :: Progression -> [[Int]]
- root :: Progression -> [[Int]]
- fromChords :: [[Int]] -> ProgressionContext
- prog :: [[Int]] -> ProgressionContext
- subKick :: Pattern Double -> IK -> (Progression -> [[Int]]) -> (Time, String, String, String) -> Pattern ValueMap
- fund :: Progression -> [[Int]]
- noteoff :: Time -> Pattern Bool -> Pattern Bool
- lineHarmony :: Pattern Double -> IK -> VoiceFunction -> [Pattern Int] -> Pattern ValueMap
- data ScaleSource
- = ExplicitScale [[Int]]
- | HarmonyAsScale Progression
- | HarmonyWithOverlap Progression (Int -> Progression -> Progression)
- melodyStateFrom :: ScaleSource -> Progression
- lead :: String -> IO CadenceState
- lead' :: String -> IO CadenceState
- parseLeadTokens :: String -> [LeadToken]
- data LeadToken
- module Harmonic.Interface.Tidal.Instruments
- module Harmonic.Interface.Tidal.Orchestra
- module Harmonic.Interface.Tidal.Utils
- renderTristrataReport :: ProgressionContext -> Maybe String
- genPReport :: IO ProgressionContext -> IO ()
- module Harmonic.Config
- generate :: CadenceState -> Int -> Text -> Double -> HarmonicContext -> IO Progression
- generateWith :: GeneratorConfig -> CadenceState -> Int -> Text -> Double -> HarmonicContext -> IO Progression
- genWith :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
- generate' :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO (Progression, GenerationDiagnostics)
- genWith' :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO (Progression, GenerationDiagnostics)
- generate'' :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO (Progression, GenerationDiagnostics)
- genWith'' :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO (Progression, GenerationDiagnostics)
- printDiagnostics :: Int -> GenerationDiagnostics -> IO ()
- data StepDiagnostic = StepDiagnostic {
- sdStepNumber :: Int
- sdPriorCadence :: String
- sdPriorRoot :: String
- sdPriorRootPC :: Int
- sdSelectedDbIntervals :: String
- sdSelectedDbMovement :: String
- sdSelectedDbFunctionality :: String
- sdGraphCount :: Int
- sdGraphTop6 :: [(String, Double)]
- sdFallbackCount :: Int
- sdFallbackTop6 :: [(String, Double, Double, Double, Double)]
- sdPoolSize :: Int
- sdEntropyUsed :: Double
- sdGammaIndex :: Int
- sdSelectedFrom :: String
- sdPosteriorRoot :: String
- sdPosteriorRootPC :: Int
- sdRenderedChord :: Maybe String
- sdTransformTrace :: Maybe TransformTrace
- sdAdvanceTrace :: Maybe AdvanceTrace
- sdTristrataIdx :: Maybe Int
- sdTristrata :: Maybe Tristrata
- sdStrataLabel :: Maybe StrataLabel
- sdMode :: Maybe Mode
- sdStrataChroma :: Maybe [PitchClass]
- sdModeChroma :: Maybe [PitchClass]
- sdSoftBoost :: Maybe Double
- sdHarmonicRootPC :: Maybe Int
- sdParentKey :: Maybe (PitchClass, ScaleFamily)
- sdModeResult :: Maybe ModeResult
- sdBarSpelling :: Maybe EnharmonicSpelling
- sdFusion :: Maybe FusionDiag
- data GenerationDiagnostics = GenerationDiagnostics {}
- data TransformTrace = TransformTrace {
- ttRawDbIntervals :: String
- ttRawDbMovement :: String
- ttRawDbFunctionality :: String
- ttRootPC :: Int
- ttRootNoteName :: String
- ttTones :: [Int]
- ttTransposedPitches :: [Int]
- ttNormalizedPs :: [Int]
- ttZeroForm :: [Int]
- ttDetectedRoot :: String
- ttFunctionality :: String
- ttFinalChord :: String
- ttStoredFunc :: String
- data AdvanceTrace = AdvanceTrace {}
- genSilent' :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
- genStandard' :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
- genVerbose' :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression
Primary interface for live coding
The modifier-based generation API. Each generator comes in three verbosity tiers, marked by the prime suffix:
gen— header + grid outputgen'— compact summarygen''— verbose traces
Modifiers compose right-to-left onto a generator:
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ gen
Triadic generation
Generation config with header + grid output (default).
s <- seek "*" $ gen s <- seek "*" $ cue start $ tonal ctx $ len 4 $ entropy 0.3 $ gen
quad :: GenConfig -> GenConfig Source #
Switch on the gen4 family: every generated bar carries a 4-note chord.
Each step first selects a triad exactly as plain gen (graph + fallback,
R filters, gamma draw), then fuses in one more R-valid palette tone —
ranked consonant-first by full-chord dissonance, drawn at the same
entropy. The walk continues from the fused chord's most-consonant
embedded triad, so the added tone can reinterpret the harmony and steer
the next step, while every graph key stays corpus-shaped (generation
stays online). A triad cue is fused once so output is uniformly 4-note;
a 4-note lead' cue passes through untouched.
Composes with the usual modifier chain. Never applies to the strata
family (genP) — strata progressions stay 3-5-7.
s <- seek "*" $ cue start $ entropy 0.4 $ quad gen'
Static grid: repeats the cue chord for len bars. No database access.
s <- seek "*" $ cue start $ len 4 $ genGrid
genFrom :: ProgressionContext -> Int -> Int -> GenConfig Source #
Regenerate a range of bars within an existing progression. The cue is inferred from the bar before the start position (wrapping).
FAMILY-AWARE: regeneration always produces uniform states of the family the source progression already is — families never mix.
pcProvenance = Just _— strata-aware path: regenerates all three layers + provenance in lockstep, with one-step lookahead at thee → e+1seam to keep the spliced bar sequence walk-graph valid underallowedNext.- uniform 4-note triad layer (gen4 source) — regen bars come out 4-note
(
_gcQuadset automatically). - uniform 3-note (gen source) — plain triad regen.
- hand-mixed cardinalities — regenerated as plain triads with a printed notice (hand-mixed material is the human aberration channel; regen does not amplify it).
s' <- seek "*" $ entropy 0.3 $ genFrom s 2 3
s' <- seek "*" $ cue start $ genFrom s 2 3 -- override inferred cue
s' <- seek "*" $ len 6 $ genFrom s 2 3 -- expand range
s' <- seek "*" $ genFrom' s 2 3 -- Standard per-step trace
s' <- seek "*" $ genFrom'' s 2 3 -- Verbose trace (+ scoreboard with attempt)
genFrom' :: ProgressionContext -> Int -> Int -> GenConfig Source #
Standard-verbosity alias of genFrom. Mirrors gen', genP' and genI'.
genFrom'' :: ProgressionContext -> Int -> Int -> GenConfig Source #
Verbose-verbosity alias of genFrom. Mirrors gen'', genP'' and genI''.
The genP paradigm (strata-first)
Three-layer generation (triad / strata / mode). The roman-numeral aliases pin the starting tristrata.
genP :: StrataLabel -> GenConfig Source #
Strata-first generation entrypoint. Seeded by a StrataLabel; produces
a ProgressionContext with distinct triad, strata, and mode layers and
pcProvenance = Just ….
s <- seek "none" $ cue start $ len 6 $ genP VI
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Silent-verbosity genP aliases, one per Roman numeral — genI pins the
starting tristrata to I, genII to II, and so on through genXI.
s <- seek "*" $ attempt 3 12 $ entropy 0.4 $ genI
Three verbosities throughout, by the usual prime convention: genI silent,
genI' standard, genI'' verbose.
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
genVIII' :: GenConfig Source #
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
Standard-verbosity Roman numeral aliases: per-step musical context plus
the grid. See genI.
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
genIII'' :: GenConfig Source #
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
genVII'' :: GenConfig Source #
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
genVIII'' :: GenConfig Source #
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
Verbose-verbosity Roman numeral aliases: full traces, the grid, and the
multi-attempt scoreboard when paired with attempt. See genI.
Generation modifiers
cue :: CadenceState -> GenConfig -> GenConfig Source #
Set starting state.
s <- seek "*" $ cue start $ gen
len :: Int -> GenConfig -> GenConfig Source #
Set progression length (number of chords).
s <- seek "*" $ len 8 $ gen
seek :: String -> GenConfig -> IO ProgressionContext Source #
Set composer blend and execute. Terminal modifier — produces IO
ProgressionContext. For legacy gen-family configs, all three layers
duplicate the generated triad progression and pcProvenance is Nothing;
the genP paradigm produces distinct strata/mode layers with Just
provenance.
s <- seek "*" $ gen
s <- seek "bach:70 debussy:30" $ cue start $ len 4 $ gen
s <- seek "none" $ cue start $ len 6 $ genVI
entropy :: Double -> GenConfig -> GenConfig Source #
Set entropy in [0, 1] — mapped affinely to the gamma sampler's shape
(shape = 1 + entropy * 9). Higher values = more unusual choices.
s <- seek "*" $ entropy 0.5 $ gen
tonal :: HarmonicContext -> GenConfig -> GenConfig Source #
Set harmonic context (R constraints).
s <- seek "*" $ tonal (hcKey "0#" $ hContext) $ gen
relStrata :: String -> GenConfig -> GenConfig Source #
Per-bar position within the dynamically-changing active tristrata. Elements
∈ {1,2,3} cycle circularly. Sets _gcLenOverride to the parsed list length
so _gcLen doesn't need to be set explicitly; len applied later clears the
override (last-writer-wins).
s <- seek "none" $ relStrata "1 1 2 2 3 3" $ genVI -- 6 bars
absStrata :: String -> GenConfig -> GenConfig Source #
Per-bar absolute strata label across all tristratas. Elements are Roman
numerals I..XI cycling circularly. Sets _gcLenOverride to the parsed
list length.
s <- seek "none" $ absStrata "I V X" $ genI -- 3 bars
sameBoost :: Double -> GenConfig -> GenConfig Source #
Override the same-strata continuity boost multiplier. Values below 1.0 favour candidates whose strata matches the previous bar's. Default 0.90. Pass 1.0 to disable the bias.
s <- seek "none" $ sameBoost 0.5 $ genVI -- strong same-strata pull
flipBoost :: Double -> GenConfig -> GenConfig Source #
Override the flip-flop boost multiplier (candidates matching the grandparent strata when the current /= previous). Default 0.80.
triBoost :: Double -> GenConfig -> GenConfig Source #
Override the same-tristrata continuity boost multiplier. Values below 1.0 favour candidates whose active tristrata matches the previous bar's. Default 0.70 (strongest of the three).
attempt :: Int -> Int -> GenConfig -> GenConfig Source #
Run multi-attempt rank-and-select generation: produce up to maxAttempts
candidate progressions, stop early once viableTarget viable attempts
(all bars ModeOk) have been collected, then return the highest-scoring
one. Scoring blends root motion, voice leading, and mode validity via
defaultWeightsOffline.
s <- seek "*" $ attempt 3 24 $ entropy 0.4 $ gen -- best of up to 24
Defaults are attempt 1 1 — i.e. the modifier is a no-op when omitted,
preserving legacy single-pass behaviour.
viability :: Double -> GenConfig -> GenConfig Source #
Set the viability quality floor used by attempt. An attempt is
viable iff psModeValidity >= 1.0 (structural invariant) and
totalScore >= floor. Default is 0.5; passing 0.0 recovers the
original structural-only viability.
s <- seek "*" $ viability 0.65 $ attempt 3 24 $ gen
Tune downward if attempt N K frequently fails to collect N viable
within K (raise K or lower the floor); tune upward if K is being hit
consistently with mediocre-quality picks (lower K or raise the floor).
Generation types
Configuration for the modifier-based generation API.
Built via modifier chains:
s <- seek "*" $ cue start $ tonal ctx $ len 4 $ entropy 0.3 $ gen
Constructors
| GenConfig | |
Fields
| |
Generation mode.
Constructors
| Fresh | Standard gen (new progression) |
| FromProg Progression !Int !Int | Regenerate range in existing triad layer |
| FromProgPC ProgressionContext !Int !Int | Regenerate range in a strata-aware context (preserves all three layers + provenance) |
| GridMode | Static repetition of cue chord |
| StrataMode StrataLabel |
|
defaultGenConfig :: GenConfig Source #
Default generation configuration.
cue: random root, major triad len: 4 seek: "*" (all composers) entropy: 0.2 tonal: hContext (chromatic)
execGenConfig :: GenConfig -> IO Progression Source #
Execute a GenConfig, producing a progression.
Thin wrapper that calls execGenConfigWithDiag (pure compute) and then
emits the appropriate diagnostics + header + grid via emitFinalised.
Single-pass callers see byte-identical output to today.
execGenConfigPC :: GenConfig -> IO ProgressionContext Source #
Terminal executor producing a ProgressionContext.
When _gcMaxAttempts > 1, dispatches through generateBest for
rank-and-select multi-attempt generation; otherwise runs a single pass.
The single-pass dispatch reads _gcMode: StrataMode runs the strata-
first traversal producing distinct layers; all other modes fall through
to execGenConfig and wrap the resulting triad Progression via
fromProgression.
Positional generation (legacy)
genSilent :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression Source #
Generate a progression with NO diagnostic output (verbosity 0 - silent mode).
genStandard :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression Source #
Generate a progression with STANDARD diagnostic output (verbosity 1).
genVerbose :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression Source #
Generate a progression with VERBOSE diagnostic output (verbosity 2).
genPrint :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression Source #
Positional generate with header + grid output (internal).
genPrint' :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression Source #
Positional generate with compact musical summary (internal).
genPrint'' :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression Source #
Positional generate with verbose traces (internal).
Context and configuration
A HarmonicContext constrains what the generator may choose. Build one
by chaining modifiers onto hContext:
ctx = invSkip 1 $ hcOvertones "E A D G" $ hcPedal "E?" $ hContext
data HarmonicContext Source #
Harmonic context defines the Rules (R) that constrain the generative space.
These filters are applied BEFORE database evaluation (R in R→E→T pipeline), limiting which cadences can even be considered as candidates.
Three-part filtering system: * overtones: Pitch candidate set (e.g., "E A D G" for bass tuning overtones) * key: Key filter applied to candidates (e.g., C, "#", "bb" for key signature) * roots: Root/bass candidate set (e.g., "E F# G" for valid root notes)
Filters use "*" as wildcard (match all). Format matches legacy Overtone.hs notation.
Constructors
| HarmonicContext | |
Fields
| |
Instances
| Show HarmonicContext Source # | |
Defined in Harmonic.Framework.Builder.Types Methods showsPrec :: Int -> HarmonicContext -> ShowS # show :: HarmonicContext -> String # showList :: [HarmonicContext] -> ShowS # | |
| Eq HarmonicContext Source # | |
Defined in Harmonic.Framework.Builder.Types Methods (==) :: HarmonicContext -> HarmonicContext -> Bool # (/=) :: HarmonicContext -> HarmonicContext -> Bool # | |
harmonicContext :: Text -> Text -> Text -> HarmonicContext Source #
Constructor for HarmonicContext.
Arguments: * overtones: Pitch set filter ("E A D G", C, "*") * key: Key signature filter (C, "#", "bb", Am, "*") * roots: Root notes filter ("E F# G", "1#", "*")
Example: harmonicContext "*" "*" "*" -- No filtering (all candidates) harmonicContext "E A D G" C "*" -- Bass tuning, C major key harmonicContext "*" "#" "E G" -- G major key, E/G roots only
hContext :: HarmonicContext Source #
Default harmonic context for Tidal live coding: all wildcards (chromatic).
Named hContext to avoid collision with TidalCycles' EventF.context field.
Use modifier functions to constrain the context:
ctx = invSkip 2
$ consonant
$ hcRoots "C E G"
$ hcKey "0#"
$ hcOvertones "E A D G"
$ hContext
Direction of dissonance drift across a generated progression.
When applied to a HarmonicContext, the generation engine filters the candidate pool at each step so that only chords with equal or greater (Dissonant) or equal or lesser (Consonant) dissonance than the current chord are preferred. Free imposes no constraint (default).
Advisory, not hard: if the drift predicate would empty the pool at a
step, the filter relaxes and that step proceeds unconstrained rather than
reaching an absorbing state (applyDriftFilter in Builder.Core). Note the
predicate is dissonanceScore — an evaluation function acting as a
filter, the documented E-inside-R leak (see ARCHITECTURE §2).
Instances
hcOvertones :: String -> HarmonicContext -> HarmonicContext Source #
Set overtone filter. Default: "*" (all pitches).
hcOvertones "E A D G" $ hContext — bass tuning overtones
hcKey :: String -> HarmonicContext -> HarmonicContext Source #
Set key filter. Default: "*" (chromatic).
hcKey "0#" $ hContext — C major
hcRoots :: String -> HarmonicContext -> HarmonicContext Source #
Set roots/bass filter. Default: "*" (all roots).
hcRoots "C E G" $ hContext — only C, E, G as bass notes
dissonant :: HarmonicContext -> HarmonicContext Source #
Modify context to trend toward increasing dissonance. Each subsequent chord should have dissonance >= the current chord; advisory — relaxes at any step where it would empty the pool.
consonant :: HarmonicContext -> HarmonicContext Source #
Modify context to trend toward decreasing dissonance. Each subsequent chord should have dissonance <= the current chord; advisory — relaxes at any step where it would empty the pool.
invSkip :: Int -> HarmonicContext -> HarmonicContext Source #
Set minimum number of non-inversion states between inversions.
invSkip 0 allows inversions at any step (default, current behaviour).
invSkip 1 requires at least 1 non-inversion between inversions.
invSkip 2 requires at least 2 non-inversions between inversions.
The starting state counts toward the counter (a non-inversion start
means the first generated step may already be an inversion with invSkip 1).
Advisory, not hard: if excluding inversions would empty the pool at a step, the spacing constraint relaxes for that step rather than halting generation.
hcPedal :: String -> HarmonicContext -> HarmonicContext Source #
Require specific pitch classes to be present in every generated chord.
Tokens are note names (C, G, Bb). A trailing ? marks a tone
as preferred rather than required — it is applied when it does not reduce
the candidate pool below a minimum viable size, and relaxed otherwise.
Advisory at the limit: the relaxation chain is preferred → required →
unfiltered (applyPedalFilter in Builder.Core), so even required tones
are dropped as a last resort at a step where enforcing them would leave no
candidates — generation never reaches an absorbing state through a pedal
constraint.
hcPedal C $ hContext — C must appear in every chord
hcPedal "C G" $ hContext — C and G must both appear
hcPedal "C G?" $ hContext — C required, G preferred
hcTristrata :: String -> HarmonicContext -> HarmonicContext Source #
Restrict the active tristrata pool for genP.
"" (default) — all 12 tristrata allowed.
"5" — lock to a single tristrata (here #5, IV-VI-X).
"1 2 5" — whitelist multiple tristrata.
"[1,2,5]" — bracket form accepted.
Parsed via parseTristrataList; unknown tokens are silently discarded.
data GeneratorConfig Source #
Configuration for the progression generator.
gcQuad switches on the gen4 family: after each triad selection, the
step fuses one R-valid palette tone into the chord (4-note output) and
the walk continues from the fused chord's most-consonant embedded triad
(see fuseState).
Historical note: the former gcPoolSize field was removed (2026-08-19)
because no generation path ever read it — the candidate pool is
deliberately unlimited (full 660-candidate fallback; see
Core).
Constructors
| GeneratorConfig | |
Instances
| Show GeneratorConfig Source # | |
Defined in Harmonic.Framework.Builder.Types Methods showsPrec :: Int -> GeneratorConfig -> ShowS # show :: GeneratorConfig -> String # showList :: [GeneratorConfig] -> ShowS # | |
| Eq GeneratorConfig Source # | |
Defined in Harmonic.Framework.Builder.Types Methods (==) :: GeneratorConfig -> GeneratorConfig -> Bool # (/=) :: GeneratorConfig -> GeneratorConfig -> Bool # | |
defaultConfig :: GeneratorConfig Source #
Default configuration.
Core music types
module Harmonic.Rules.Types.Pitch
module Harmonic.Rules.Types.Harmony
Voice leading (cyclic DP paradigms)
voiceLeadingCost :: [Int] -> [Int] -> Int Source #
Calculate the voice leading cost between two chords.
Cost components: * Base: sum of absolute MIDI movements per voice. * Parallel penalty: +3 for each parallel perfect 5th / octave between ANY voice pair (not just adjacent), when at least one voice moves. * Large leap penalty: +2 per voice moving > 4 semitones. * Register-exchange penalty: +4 per adjacent voice pair where both voices move ≥5 semitones in opposite directions (split-leap pattern producing register inversion). Note: not classical "voice crossing" — sorted MIDI voicings have no voice identity to cross — but the same musical effect of register-swapping leaps. * Contrary motion bonus: −1 per voice pair (any pair) where both voices move ≤4 semitones in opposite directions (modest divergence). * Stepwise motion bonus: −1 per stepping voice (movement ∈ {1, 2}) when ≥2 voices step. Single-voice steps contribute 0.
Magnitudes calibrated to compose: contrary motion and register exchange are deliberately disjoint by magnitude (≤4 vs ≥5 thresholds), aligning with the leap-penalty trigger so the same motion is never both rewarded and penalised. They also differ in pair scope by design: register exchange scans ADJACENT pairs only (a register swap is a neighbouring-voices phenomenon), while contrary motion rewards ANY pair.
The total is floored at 1 for any actual motion (from /= to): bonuses
could otherwise exceed base + penalties and drive a moving transition
below the held-chord cost of 0 — inverting the musical preference. A
held chord ("available static movement") is always strictly cheapest;
bonuses still discriminate among positive-cost alternatives. The floor
applies to the TOTAL only — component bonuses stay un-clamped inside
the sum (e.g. [0,4,7]→[-1,2,7] = base 3 + stepwise −1 = 2).
Cross-cardinality transitions (mixed-set seams: lead' cues, hand-built
fromChords material) are costed by optimal monotone padding: the smaller
sorted voicing is expanded by duplicating tones per the minimal-distance
non-crossing alignment in which every voice of BOTH chords participates
(alignVoices), then the full cost above runs verbatim on the aligned
pair. An extra voice pays exactly its distance to the tone it splits
from (a literal unison doubling is free); no voice can appear or vanish
unpenalised. Historical note: this branch was a flat 999 sentinel,
which in the DP acted as "ignore this edge" — seam registers were
decided by downstream edges alone and the cyclic wrap objective was
silently disabled on mixed material.
cyclicCost :: [[Int]] -> Int Source #
Calculate cyclic cost: total cost including wrap-around from last to first. This is essential for loop-aware optimization.
From the evaluation document:
"Adding wrap-around cost to the voice leading solver solves the drift
issue elegantly. It forces the algorithm to find a path that is not
just locally optimal, but topologically closed."
voiceMovement :: Int -> Int -> Int Source #
Calculate the movement for a single voice between two concrete pitches. Movement is measured in absolute semitones (not mod 12 since we're working with concrete pitches in the [0,36] range).
minimalMovement :: PitchClass -> PitchClass -> Int Source #
Calculate minimal movement between two pitch class values (mod 12). Exported API; currently unused inside the engine (kept for REPL and downstream use).
allVoicings :: [Int] -> [[Int]] Source #
Generate all valid voicings for a pitch-class set of any cardinality.
Each pitch class is placed at its pitchPlacements octaves (PCs 0-6
get 2 placements in [12, 30]; PCs 7-11 get 3 in [7, 35]) — candidate
count is the per-PC placement product (2^a·3^b: typically 12 for a
triad, 36 for a tetrad, 72 for a 5-PC set), NOT 3^N. The key-dependent
window asymmetry is a known calibration; widening it changes every
solved voicing globally and is deferred behind a before/after
listening protocol.
Results are sorted low-to-high and deduplicated.
Historical note: this was hard-coded to 3 notes, with non-triads falling
back to the single candidate [sort pcs] pinned in octave [0,11] — which
collapsed bars 2..n of any multi-bar 4+-note progression ~2 octaves below
bar 1 under flow/grid (bar 1 goes through initialCompact, the rest
through here, then normalizeByFirstRoot applies one uniform shift).
initialCompact :: Int -> [Int] -> [Int] Source #
Create initial compact voicing: root in bass in target octave (12-23), upper voices stacked compactly above.
solveRoot :: [[Int]] -> [[Int]] Source #
Solve with root always in bass (root paradigm). Filters candidates at each position to only those where bass note mod 12 == root PC. Result is normalized so first chord's root is in [-12,-1].
solveFlow :: [[Int]] -> [[Int]] Source #
Solve FLOW paradigm using cyclic DP:
Smoothest voice leading with any inversion allowed for bars 1..n-1.
Bar 0 is anchored to the compact root-position voicing
(initialCompact) so the progression's starting register is
predictable and normalizeByFirstRoot has a stable anchor.
Voice crossings permitted in subsequent bars for optimal smoothness.
Result is normalized so first chord's root is in [-12, -1].
Progressions and scales
module Harmonic.Rules.Types.Scale
Interactive behaviour
Filter functions
String-friendly versions for TidalCycles
overtones :: String -> [PitchClass] Source #
Parse overtones from a String (Tidal-friendly) Example: overtones "E A D G" -> bass tuning overtones
key :: String -> [PitchClass] Source #
Parse key from a String (Tidal-friendly) Example: key "#" -> G major, key "bb" -> Bb major
funds :: String -> [PitchClass] Source #
Parse fundamentals from a String (Tidal-friendly) Example: funds "E F# G" -> [4, 6, 7]
Text versions
parseOvertones :: Text -> [PitchClass] Source #
Parse overtones with 3 overtones (default: root, P5, M3)
parseFunds :: Text -> [PitchClass] Source #
Parse fundamentals with 3 overtones (default)
parseTuning :: Text -> [PitchClass] Source #
Parse tuning with 3 overtones (default: root, P5, M3 — the distinct pitch classes of the playable tapped-harmonic domain)
isWildcard :: Text -> Bool Source #
Check if a filter string is a wildcard (matches everything)
Overtone annotation support
parseTuningNamed :: Text -> [(String, Int)] Source #
Parse a tuning string preserving string names for overtone annotation. Case is preserved for string identification (uppercase = lower octave, lowercase = higher octave per thesis convention).
Examples:
"E A D G" → [(E,4), (A,9), (D,2), (G,7)]
"E A e G B" → [(E,4), (A,9), ("e",4), (G,7), (B,11)]
"*" → [] (wildcard has no named strings)
Database interface
connectNeo4j :: IO Pipe Source #
Open a Bolt connection to the local Neo4j on port 7687, using the credentials in Harmonic.Config. Every online generation path needs one.
Ingestion pipeline
Corpus ingestion. Not needed to play — see Harmonic.Rules.Import.CSV.
module Harmonic.Rules.Import.CSV
TidalCycles interface
Pattern-level operations
type VoiceFunction = Progression -> [[Int]] Source #
Voice function type: extracts integer pitch sequences from progression
voiceRange :: (Int, Int) -> Pattern Int -> Pattern Int Source #
Filter pattern events by MIDI note range
Arguments
| :: (Double, Double) | Kinetics range |
| -> IK | Performance context (kinetics + chord selection) |
| -> (Int, Int) | Degree-index trim for the input patterns (scale degrees, not MIDI; instrument-range clipping happens later via clip) |
| -> Layer | Progression layer to voice (T | S | M) |
| -> VoiceFunction | Voice function (flow, root, etc.) |
| -> (Progression -> Progression) | Progression modifier (overlapF 0, id, etc.) |
| -> [Pattern Int] | Input patterns to harmonize |
| -> Pattern ValueMap |
Render scale-degree patterns into a playable ControlPattern, reading
pitches from the progression under the given voicing strategy.
The workhorse of the Tidal interface: every orchestral instrument in Harmonic.Interface.Tidal.Orchestra is a thin wrapper around it.
d1 $ arrange (0,1) k (-9,9) T flow id ["0 1 2 3"]
Arguments
| :: (Double, Double) | Kinetics range |
| -> IK | Performance context |
| -> (Int, Int) | Degree-index trim for the input patterns (scale degrees, not MIDI; instrument-range clipping happens later via clip) |
| -> Layer | Progression layer (T | S | M) |
| -> VoiceFunction | Voice function |
| -> (Progression -> Progression) | Progression modifier |
| -> [Pattern Int] | Input patterns to harmonize |
| -> Pattern ValueMap |
Map notes through chords using squeeze, with kinetics range gating.
Same kinetics/modifier pattern as arrange, but uses squeeze strategy:
each chord slot gets the full input pattern compressed to fit.
parallel :: Pattern Note -> ControlPattern -> ControlPattern Source #
Stack fixed-interval parallel voices over an arranged ControlPattern.
The offset pattern is the FULL voice spec in absolute semitones: each note
of pat is replaced by one copy per simultaneous offset, shifted by that
offset. Include 0 to retain the original note; omit it to drop the root.
Comma = simultaneous voices, space = time-sequenced offsets (standard
mininotation, natively evaluated). Applied post-voicing/post-range-filter,
so offsets are not gated by the arrange MIDI range.
parallel "0 7" $ arrange ... -- root + perfect fifth above parallel "7" $ arrange ... -- fifth only (root dropped) parallel "[0,-5,4]" $ arrange ... -- root, fourth below, major third above
warp :: String -> Pattern Int Source #
Parse a mininotation chord selection pattern (bar-relative).
The /N divisor specifies the number of bars the pattern spans.
let r = warp "[1 2 3 4]/4" -- 4 chords over 4 bars (1 per bar) let r = warp "[1 2]/8" -- 2 chords over 8 bars (4 bars each)
rep :: ProgressionContext -> Pattern Time -> Pattern Int Source #
Generate a sequential chord selection pattern from a progression. Auto-derives length from the progression. Timing is bar-relative.
let r = rep s4 1 -- 4 chords over 4 bars (1 bar each) let r = rep s4 0.5 -- 4 chords over 2 bars (half bar each)
lookupChordAt :: Time -> Pattern Int -> Int Source #
Point-query a chord selection pattern at a specific time.
Returns the chord index (0-indexed) active at time t.
Falls back to chord 0 if no events found.
lookupChord :: ProgressionContext -> Int -> Chord Source #
Lookup a chord from a progression context by index with modulo wrap. Operates on the triad layer (the harmonic content).
lookupProgression :: ProgressionContext -> Pattern Int -> Pattern [Int] Source #
Lookup progression (triad layer) as a pattern of voicings via flow.
overlapF :: Int -> Progression -> Progression Source #
Forward overlap: merge pitches from n bars ahead
Form and kinetics
A node in a form definition: a point in time with kinetics level, dynamic level, active progression, and the transition style of the section starting here.
Constructors
| FormNode | |
Fields
| |
A node's position in time — wall-clock Secs or musical Bars (4/4).
Resolved to Tidal cycles at realization (see formK). Mix freely in one form.
data Transition Source #
How a section moves to the next node: Smooth (ramped) or Snap
(hold this node's value, then jump on the next node's exact time).
Instances
| Show Transition Source # | |
Defined in Harmonic.Interface.Tidal.Form Methods showsPrec :: Int -> Transition -> ShowS # show :: Transition -> String # showList :: [Transition] -> ShowS # | |
| Eq Transition Source # | |
Defined in Harmonic.Interface.Tidal.Form | |
Realized form: continuous and discrete signals for live performance.
Constructors
| Kinetics | |
Fields
| |
type IK = (Kinetics, Pattern Int) Source #
Performance context: Kinetics bundled with chord selection pattern.
Reduces parameter threading — r and k are always passed together.
at :: Double -> Double -> Double -> ProgressionContext -> FormNode Source #
Form node builders. Time unit and transition are orthogonal:
at/at' take wall-clock seconds, rh/rh' take bars (rehearsal marks, 4/4);
unprimed = smooth transition, primed = snap. at is unchanged from before.
at 0 0 0 s seconds, smooth rh 8 0.5 0.5 s bars, smooth
at' 60 1 1 s seconds, snap rh' 16 0.9 0.9 s bars, snap
at' :: Double -> Double -> Double -> ProgressionContext -> FormNode Source #
Form node builders. Time unit and transition are orthogonal:
at/at' take wall-clock seconds, rh/rh' take bars (rehearsal marks, 4/4);
unprimed = smooth transition, primed = snap. at is unchanged from before.
at 0 0 0 s seconds, smooth rh 8 0.5 0.5 s bars, smooth
at' 60 1 1 s seconds, snap rh' 16 0.9 0.9 s bars, snap
rh :: Double -> Double -> Double -> ProgressionContext -> FormNode Source #
Form node builders. Time unit and transition are orthogonal:
at/at' take wall-clock seconds, rh/rh' take bars (rehearsal marks, 4/4);
unprimed = smooth transition, primed = snap. at is unchanged from before.
at 0 0 0 s seconds, smooth rh 8 0.5 0.5 s bars, smooth
at' 60 1 1 s seconds, snap rh' 16 0.9 0.9 s bars, snap
rh' :: Double -> Double -> Double -> ProgressionContext -> FormNode Source #
Form node builders. Time unit and transition are orthogonal:
at/at' take wall-clock seconds, rh/rh' take bars (rehearsal marks, 4/4);
unprimed = smooth transition, primed = snap. at is unchanged from before.
at 0 0 0 s seconds, smooth rh 8 0.5 0.5 s bars, smooth
at' 60 1 1 s seconds, snap rh' 16 0.9 0.9 s bars, snap
iK :: Double -> [FormNode] -> Pattern Int -> IK Source #
Construct performance context from BPM, form nodes, and chord selection.
k = iK tempo [at 0 0 0 s, at 30 1 1 s] (warp "[1 2 3 4]/8")
Arguments
| :: Pattern Double | Kinetics signal (0-1, live) |
| -> Pattern Double | Dynamics signal (0-1, live) |
| -> ProgressionContext | Active 3-layer progression |
| -> Pattern Int | Chord-selection pattern |
| -> IK |
Live kinetics: build IK from reactive kinetics/dynamics signals. Bypasses form interpolation — use when the envelope is driven by live input (e.g. MIDI CC) rather than a static keyframed form.
k = lK exP exP s r -- pedal drives both kinetics and dynamics
formK :: Double -> [FormNode] -> Kinetics Source #
Realize a form definition into Kinetics signals at a given BPM.
Single-node forms produce constant signals (global state).
Multi-node forms produce per-segment signals — smooth (ramp) or snap (step)
per each node's fnTrans — and a step-function progression, looping at the
form's total duration. Time is resolved from each node's FormTime.
ki :: (Double, Double) -> IK -> Pattern a -> Pattern a Source #
Range gate: mask a pattern by kinetics signal level. Events pass only when kSignal is within the (lo, hi) range.
slate :: (Double, Double) -> IK -> [Pattern a] -> Pattern a Source #
Gated stack: stack patterns and gate by kinetics range.
withForm :: IK -> (ProgressionContext -> Pattern ValueMap) -> Pattern ValueMap Source #
Bridge helper: apply a function taking ProgressionContext to a Kinetics context.
Uses innerJoin to reactively switch when the form changes progressions.
Arranger functions (voicing paradigms)
rotate :: Int -> ProgressionContext -> ProgressionContext Source #
Rotate a progression by n bars (positive = left, negative = right)
excerpt :: Int -> Int -> ProgressionContext -> ProgressionContext Source #
Extract bars start to end (1-indexed, inclusive)
insert :: CadenceState -> Int -> ProgressionContext -> ProgressionContext Source #
Insert a CadenceState at position (1-indexed), replacing the existing one
switch :: Int -> Int -> ProgressionContext -> ProgressionContext Source #
Switch two bars at positions m and n (1-indexed)
clone :: Int -> Int -> ProgressionContext -> ProgressionContext Source #
Clone bar m to position n (overwrites n with contents of m)
extract :: Int -> ProgressionContext -> CadenceState Source #
Extract a single CadenceState at index (1-indexed, modulo wrap) from the triad layer
transposeP :: Int -> ProgressionContext -> ProgressionContext Source #
Transpose a progression by n semitones
reverse :: ProgressionContext -> ProgressionContext Source #
Reverse a progression
fuse :: [ProgressionContext] -> ProgressionContext Source #
Fuse multiple progressions into one (concatenation)
fuse2 :: ProgressionContext -> ProgressionContext -> ProgressionContext Source #
Binary fuse for convenience in live coding
interleave :: ProgressionContext -> ProgressionContext -> ProgressionContext Source #
Interleave two progressions (alternating chords) Example: interleave [A,B,C] [X,Y,Z] = [A,X,B,Y,C,Z]
expandP :: Int -> ProgressionContext -> ProgressionContext Source #
Expand a progression by repeating each chord n times
progOverlap :: Int -> Progression -> Progression Source #
Bidirectional overlap: merge pitches from n bars in both directions
progOverlapF :: Int -> Progression -> Progression Source #
Forward-only overlap: merge pitches from n bars ahead
progOverlapB :: Int -> Progression -> Progression Source #
Backward-only overlap: merge pitches from n bars behind
grid :: Progression -> [[Int]] Source #
GRID paradigm: Root locked in bass with smooth compact voice leading. Uses cyclic DP to find globally optimal voicings. First chord starts compact with root in bass; all subsequent chords maintain root in bass with minimal voice movement.
flow :: Progression -> [[Int]] Source #
FLOW paradigm: Smoothest voice leading with any inversion allowed. Uses cyclic DP to find globally optimal voicings. Voice crossings permitted for optimal smoothness; bass doesn't need to be the root if an inversion provides smoother voice leading.
lite :: Progression -> [[Int]] Source #
LITE paradigm: Literal voicings with first-root normalization. Returns pitches as stored, but normalized so first chord's root is in [-12,-1]. No voice leading optimization applied (only octave normalization).
literal :: Progression -> [[Int]] Source #
Alias for lite (legacy compatibility)
root :: Progression -> [[Int]] Source #
ROOT paradigm: Root note only (root pitch class per chord). Extracts the root note (first element, mod 12) from each chord. Returns as single-element lists in [0,11] range.
Explicit progression construction
fromChords :: [[Int]] -> ProgressionContext Source #
Construct a Progression from explicit pitch-class sets.
This is the main function for composing/arranging workflow (not generation).
Takes an enharmonic spelling and a list of chord pitch-class sets,
returns a Progression ready for arrange.
Example:
fromChords [[0,4,7], [5,9,0], [7,11,2]]
--> C major → F major → G major
prog :: [[Int]] -> ProgressionContext Source #
Legacy alias for fromChords (matches legacy prog function)
Groove interface (drums and sub bass)
Arguments
| :: Pattern Double | Dynamics pattern (> 0 = sub active) |
| -> IK | Performance context (kinetics + chord selection) |
| -> (Progression -> [[Int]]) | Voice strategy (fund or bass) |
| -> (Time, String, String, String) | Kick placement pattern string |
| -> Pattern ValueMap |
Groove interface using patterned chord selection with kinetics gating.
CC64 sustain mechanism with chord selection from IK.
Sub on/off patterns and kick pattern are bar-relative:
"[1]/2" = one onset every 2 bars, "1*4" = 4 kicks per bar.
Chord selection uses innerJoin — we WANT new note-ons when the
chord changes (unlike melodic instruments where sustain across
boundaries is desirable).
The progression is read from kProg via innerJoin.
Sub is gated at (0.1, 1) and kick at (0.2, 1) via ki.
fund :: Progression -> [[Int]] Source #
Extract harmonic roots regardless of inversion. Always returns the fundamental root note from CadenceState.
noteoff :: Time -> Pattern Bool -> Pattern Bool Source #
Truncate each gate onset's note length to at most 1/n of a bar (bar = 4
cycles), else extend it to the next onset. Only True onsets sound; a
truncated tail is a rest; onsets are not moved. Pair with # legato 1 on
sustaining instruments to hear the length. Precondition: n > 0.
Bar patterns are written "/4" (1 cycle = 1 beat, 1 bar = 4 cycles), so
e.g. noteoff 4 caps each hit at a quarter note (1 cycle):
noteoff 4 "[[1 0 0 0] [0 0 0 0] [1 0 0 0] [1 0 0 0]]\/4" == "[1 0 1 1]\/4"
Walking-bass line interface
Arguments
| :: Pattern Double | Dynamics scalar (amp multiplier) |
| -> IK | Performance context (kinetics + chord-selection) |
| -> VoiceFunction | Beat-1 voicing (fund or root) |
| -> [Pattern Int] | Polyphonic layers (1-indexed beat positions) |
| -> Pattern ValueMap |
Walking-bass arrangement with kinetics gating.
Fixed to the double-bass register (E1..C3, MIDI 28..48) inside walkLine;
the emitted Tidal note values are pre-shifted by tidalNoteOffset so
this range is audibly true at default synth tuning — no |- oct n
compensation needed. Runtime register shifts via |+ oct n / |- oct n
on the launcher side still compose normally.
For octatripentatonic progressions (pcProvenance = Just), the Pass-3
connector pool is reweighted: strata pitches (5 PCs) are most preferred,
overlap (cyclic union of adjacent chord-PCs) is neutral, mode pitches
(7 PCs) are admissible with a mild penalty, and chromatic ±1 approaches
outside any of those sets are removed entirely. For gen (legacy)
progressions the line is byte-identical to the previous behaviour.
Entropy is derived internally from the progression's harmonic character.
Scale source (switch mechanism)
data ScaleSource Source #
Scale source for melody mapping. Enables flexible melody construction by allowing harmony (with optional overlap) to serve as the scale source instead of explicit scale definitions.
Constructors
| ExplicitScale [[Int]] | User-defined scale per chord |
| HarmonyAsScale Progression | Use harmony chords as scales |
| HarmonyWithOverlap Progression (Int -> Progression -> Progression) | Use harmony with overlap function applied |
melodyStateFrom :: ScaleSource -> Progression Source #
Create melody state from scale source. Converts a ScaleSource into a Progression suitable for melody arrangement.
Starting state construction
lead :: String -> IO CadenceState Source #
Construct a CadenceState from a human-readable string.
Parses root, quality, and movement from space-separated tokens. Unspecified components fall through to randomness. Prints "root quality" to the console after construction.
Examples:
start <- lead "E min (5)" -- E minor, ascending 5th
start <- lead "E min" -- E minor, random movement
start <- lead "min" -- random root, minor quality, random movement
start <- lead E -- E, random quality, random movement
start <- lead "" -- fully random
start <- lead "(5)" -- random root and quality, fixed movement 5
lead' :: String -> IO CadenceState Source #
Construct a CadenceState from an explicit list of note names —
the arbitrary-cardinality counterpart to lead. The first note is the
root/bass; the rest become root-relative intervals (any count, so
4-note cues for gen4 and beyond are first-class). Never truncates:
builds via mkCadenceStatePCs, so all pitch content survives into the
cue. Enharmonics follow the typed accidentals (Eb spells flat,
D sharp; double accidentals accepted and resolved). An optional
(N) token fixes the approach movement, otherwise it is randomized
exactly like lead. Unrecognized tokens are reported and skipped;
with no valid notes at all, falls back to fully random lead.
Examples:
start <- lead' "Eb Gb Bb Db" -- Eb m7, random movement
start <- lead' "A C E G (5)" -- A m7, ascending 5th approach
start <- lead' "C E G" -- plain triad, same as lead "C maj"
parseLeadTokens :: String -> [LeadToken] Source #
Parse a lead string into a list of typed tokens. Each space-separated token is independently classified as root, quality, or movement.
Instruments and orchestra
renderTristrataReport :: ProgressionContext -> Maybe String Source #
Render a multi-line report of the per-bar provenance of a
ProgressionContext: for each bar, the tristrata index, its three strata,
and the selected strata for that bar. Returns Nothing when the context
has no provenance (e.g., a legacy gen result).
genPReport :: IO ProgressionContext -> IO () Source #
module Harmonic.Config
Internal (advanced use only)
Tuple-returning versions for manual diagnostics extraction.
Arguments
| :: CadenceState | Starting state (root + quality) |
| -> Int | Number of chords |
| -> Text | Composer blend string |
| -> Double | Entropy (gamma shape) |
| -> HarmonicContext | R constraints |
| -> IO Progression |
Generate a harmonic progression from a starting state.
Arguments: * start: Initial CadenceState (defines starting root and quality) * len: Number of chords to generate * composerStr: Composer blend string ("bach:70 debussy:30") * entropy: Gamma shape parameter (higher = more unusual choices) * context: HarmonicContext filters (R constraints)
Algorithm: 1. Parse composer weights 2. For each step: query graph, apply R filter, apply E weights, gamma select 3. Apply voice leading optimization to the complete chain
Returns: Progression type (Phase B)
generateWith :: GeneratorConfig -> CadenceState -> Int -> Text -> Double -> HarmonicContext -> IO Progression Source #
Generate with custom configuration
Simplified algorithm: 1. Start with user-provided CadenceState 2. For each step: build candidate pool, gamma-select next cadence 3. Candidate pool = graph transitions (filtered) + consonanceFallback (unlimited — the pool is never truncated)
genWith :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression Source #
String-friendly generateWith for TidalCycles live coding.
generate' :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO (Progression, GenerationDiagnostics) Source #
Generate a progression returning both result and diagnostics (internal).
This is the core internal function that generates progressions and collects standard-level diagnostics (per-step candidate pools, selections, rendered chords).
For most users, use the unified interface instead:
* genSilent - for silent generation
* genStandard - for standard diagnostics
* genVerbose - for verbose diagnostics
genWith' :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO (Progression, GenerationDiagnostics) Source #
Generate with custom configuration, returning diagnostics tuple (internal).
generate'' :: CadenceState -> Int -> String -> Double -> HarmonicContext -> IO (Progression, GenerationDiagnostics) Source #
Generate a progression with maximum diagnostic traces (internal).
Like 'generate'' but populates full transform and advance traces for debugging. This function collects: * All standard diagnostics (per-step candidate pools, selections) * Full transform traces (DB intervals, transposition, normalization, zero-form) * Full advance traces (root motion PC arithmetic, enharmonic spelling)
This is SLOWER than 'generate'' due to extra tracing computation. Use only for debugging chord name discrepancies or voice leading issues.
genWith'' :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO (Progression, GenerationDiagnostics) Source #
Generate with custom configuration and maximum diagnostics (internal).
printDiagnostics :: Int -> GenerationDiagnostics -> IO () Source #
Print diagnostics collected during generation.
Selects output level based on verbosity parameter:
- 0 - Silent
- No output
- 1 - Standard
- Per-step candidate pools, selections, rendered chords
- 2 - Verbose
- Standard plus transform and advance traces
Useful for manually reprinting diagnostics after extraction from tuple, or batch processing multiple results at different verbosity levels.
data StepDiagnostic Source #
Diagnostic information for a single generation step
Constructors
| StepDiagnostic | |
Fields
| |
Instances
| Show StepDiagnostic Source # | |
Defined in Harmonic.Framework.Builder.Types Methods showsPrec :: Int -> StepDiagnostic -> ShowS # show :: StepDiagnostic -> String # showList :: [StepDiagnostic] -> ShowS # | |
| Eq StepDiagnostic Source # | |
Defined in Harmonic.Framework.Builder.Types Methods (==) :: StepDiagnostic -> StepDiagnostic -> Bool # (/=) :: StepDiagnostic -> StepDiagnostic -> Bool # | |
data GenerationDiagnostics Source #
Complete diagnostics for a generation run
Constructors
| GenerationDiagnostics | |
Fields
| |
Instances
| Show GenerationDiagnostics Source # | |
Defined in Harmonic.Framework.Builder.Types Methods showsPrec :: Int -> GenerationDiagnostics -> ShowS # show :: GenerationDiagnostics -> String # showList :: [GenerationDiagnostics] -> ShowS # | |
data TransformTrace Source #
Transform trace captures intermediate values in fromCadenceState → toTriad pipeline. Used for maximum verbosity debugging (gen''). Includes raw DB data plus all transformation stages.
Constructors
| TransformTrace | |
Fields
| |
Instances
| Show TransformTrace Source # | |
Defined in Harmonic.Framework.Builder.Types Methods showsPrec :: Int -> TransformTrace -> ShowS # show :: TransformTrace -> String # showList :: [TransformTrace] -> ShowS # | |
| Eq TransformTrace Source # | |
Defined in Harmonic.Framework.Builder.Types Methods (==) :: TransformTrace -> TransformTrace -> Bool # (/=) :: TransformTrace -> TransformTrace -> Bool # | |
data AdvanceTrace Source #
Advance trace captures intermediate values in root advancement. Used for maximum verbosity debugging (gen'').
Constructors
| AdvanceTrace | |
Fields
| |
Instances
| Show AdvanceTrace Source # | |
Defined in Harmonic.Framework.Builder.Types Methods showsPrec :: Int -> AdvanceTrace -> ShowS # show :: AdvanceTrace -> String # showList :: [AdvanceTrace] -> ShowS # | |
| Eq AdvanceTrace Source # | |
Defined in Harmonic.Framework.Builder.Types | |
genSilent' :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression Source #
Silent mode with custom GeneratorConfig.
genStandard' :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression Source #
Standard diagnostics with custom GeneratorConfig.
genVerbose' :: GeneratorConfig -> CadenceState -> Int -> String -> Double -> HarmonicContext -> IO Progression Source #
Verbose diagnostics with custom GeneratorConfig.