{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE InstanceSigs #-}

-- |
-- Module      : Harmonic.Rules.Types.Harmony
-- Description : Chord, Cadence, and their Concrete State representations
--
-- This module establishes the Abstract\/Concrete distinction:
--
--   Abstract (transposition-invariant):
--
--     * 'Chord'   - A pitch structure defined by intervals from root
--     * 'Cadence' - A movement type and target chord quality
--
--   Concrete (rooted in pitch space):
--
--     * 'ChordState'   - A Chord with a specific root pitch
--     * 'CadenceState' - A Cadence with a specific root pitch
--
-- == Academic Lineage
--
-- /Data Science In The Creative Process/ (South, 2018): the MusicData
-- module's chord naming conventions (@nameFuncTriad@, @nameFuncChord@)
-- ported verbatim from legacy MusicData.hs (lines 443-479).
--
-- /The Harmonic Algorithm/ (South, 2016): the concept of harmonic
-- extrapolation categories (Simple, Complex, Impractical) which informed
-- the chord quality taxonomy used here.

module Harmonic.Rules.Types.Harmony
  ( -- * Functionality (Chord Quality)
    Functionality
  , toFunctionality
  , toFunctionalityChord
  
    -- * Abstract Types
  , Chord(..)
  , Cadence(..)
  
    -- * Movement
  , Movement(..)
  , toMovement
  , fromMovement
  
    -- * Enharmonic Spelling
  , EnharmonicSpelling(..)
  , EnharmonicPreference(..)
  , enharmonicPreference
  , selectEnharm
  , defaultEnharm
  , spellingToPreference
  , enharmonicFunc
  , inferSpelling
  , noteNameImpliesSpelling
  , isAmbiguousPattern

    -- * Concrete State Types
  , ChordState(..)
  , CadenceState(..)
  
    -- * Triad Construction (exactly 3 pitches, with reduction)
  , toTriad
  , flatTriad
  , sharpTriad
  
    -- * Chord Construction (preserves all pitches)
  , toChord
  , flatChord
  , sharpChord
  
    -- * Cadence Construction
  , toCadence
  
    -- * State Conversion
  , fromChordState
  , fromCadenceState
  , initCadenceState
  , mkCadenceStatePCs

    -- * Walk Projection (gen4)
  , walkTriadCadence
  , walkTriadState

    -- * Tracing (for maximum verbosity diagnostics)
  , ToTriadTrace(..)
  , fromCadenceStateTraced
  
    -- * DB Serialization (compatible with Neo4j format)
  , constructCadence
  , corpusFunctionality
  , deconstructCadence
  
    -- * Utilities
  , rootNote
  , inversions
  , isInversion
  , normalForm
  , primeForm
  , zeroFormPC
  ) where

import GHC.Generics (Generic)
import Data.Function (on)
import Data.List (sort, sortBy)
import qualified Data.List as List
import Data.Maybe (fromMaybe, listToMaybe)
import Control.Applicative ((<|>))
import qualified Data.IntMap.Strict as IM
import qualified Data.IntSet as IS

import Harmonic.Rules.Types.Pitch

-------------------------------------------------------------------------------
-- Enharmonic Spelling
-------------------------------------------------------------------------------

-- |Enharmonic spelling preference (sharp or flat)
-- Stored in CadenceState to enable consistent spelling throughout a progression
data EnharmonicSpelling = SharpSpelling | FlatSpelling
  deriving (EnharmonicSpelling -> EnharmonicSpelling -> Bool
(EnharmonicSpelling -> EnharmonicSpelling -> Bool)
-> (EnharmonicSpelling -> EnharmonicSpelling -> Bool)
-> Eq EnharmonicSpelling
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
== :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
$c/= :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
/= :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
Eq, Eq EnharmonicSpelling
Eq EnharmonicSpelling =>
(EnharmonicSpelling -> EnharmonicSpelling -> Ordering)
-> (EnharmonicSpelling -> EnharmonicSpelling -> Bool)
-> (EnharmonicSpelling -> EnharmonicSpelling -> Bool)
-> (EnharmonicSpelling -> EnharmonicSpelling -> Bool)
-> (EnharmonicSpelling -> EnharmonicSpelling -> Bool)
-> (EnharmonicSpelling -> EnharmonicSpelling -> EnharmonicSpelling)
-> (EnharmonicSpelling -> EnharmonicSpelling -> EnharmonicSpelling)
-> Ord EnharmonicSpelling
EnharmonicSpelling -> EnharmonicSpelling -> Bool
EnharmonicSpelling -> EnharmonicSpelling -> Ordering
EnharmonicSpelling -> EnharmonicSpelling -> EnharmonicSpelling
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: EnharmonicSpelling -> EnharmonicSpelling -> Ordering
compare :: EnharmonicSpelling -> EnharmonicSpelling -> Ordering
$c< :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
< :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
$c<= :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
<= :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
$c> :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
> :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
$c>= :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
>= :: EnharmonicSpelling -> EnharmonicSpelling -> Bool
$cmax :: EnharmonicSpelling -> EnharmonicSpelling -> EnharmonicSpelling
max :: EnharmonicSpelling -> EnharmonicSpelling -> EnharmonicSpelling
$cmin :: EnharmonicSpelling -> EnharmonicSpelling -> EnharmonicSpelling
min :: EnharmonicSpelling -> EnharmonicSpelling -> EnharmonicSpelling
Ord, Int -> EnharmonicSpelling -> ShowS
[EnharmonicSpelling] -> ShowS
EnharmonicSpelling -> String
(Int -> EnharmonicSpelling -> ShowS)
-> (EnharmonicSpelling -> String)
-> ([EnharmonicSpelling] -> ShowS)
-> Show EnharmonicSpelling
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EnharmonicSpelling -> ShowS
showsPrec :: Int -> EnharmonicSpelling -> ShowS
$cshow :: EnharmonicSpelling -> String
show :: EnharmonicSpelling -> String
$cshowList :: [EnharmonicSpelling] -> ShowS
showList :: [EnharmonicSpelling] -> ShowS
Show, ReadPrec [EnharmonicSpelling]
ReadPrec EnharmonicSpelling
Int -> ReadS EnharmonicSpelling
ReadS [EnharmonicSpelling]
(Int -> ReadS EnharmonicSpelling)
-> ReadS [EnharmonicSpelling]
-> ReadPrec EnharmonicSpelling
-> ReadPrec [EnharmonicSpelling]
-> Read EnharmonicSpelling
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS EnharmonicSpelling
readsPrec :: Int -> ReadS EnharmonicSpelling
$creadList :: ReadS [EnharmonicSpelling]
readList :: ReadS [EnharmonicSpelling]
$creadPrec :: ReadPrec EnharmonicSpelling
readPrec :: ReadPrec EnharmonicSpelling
$creadListPrec :: ReadPrec [EnharmonicSpelling]
readListPrec :: ReadPrec [EnharmonicSpelling]
Read, (forall x. EnharmonicSpelling -> Rep EnharmonicSpelling x)
-> (forall x. Rep EnharmonicSpelling x -> EnharmonicSpelling)
-> Generic EnharmonicSpelling
forall x. Rep EnharmonicSpelling x -> EnharmonicSpelling
forall x. EnharmonicSpelling -> Rep EnharmonicSpelling x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. EnharmonicSpelling -> Rep EnharmonicSpelling x
from :: forall x. EnharmonicSpelling -> Rep EnharmonicSpelling x
$cto :: forall x. Rep EnharmonicSpelling x -> EnharmonicSpelling
to :: forall x. Rep EnharmonicSpelling x -> EnharmonicSpelling
Generic)

-- |Convert EnharmonicSpelling to the actual function (PitchClass -> NoteName)
-- |Classify a pitch class by its natural enharmonic preference.
-- C (PC 0) is AMBIGUOUS - it adopts the pairing's preference (prior or posterior).
-- All other pitch classes have definite preferences.
data EnharmonicPreference = FlatPref | SharpPref | AmbiguousPref
  deriving (EnharmonicPreference -> EnharmonicPreference -> Bool
(EnharmonicPreference -> EnharmonicPreference -> Bool)
-> (EnharmonicPreference -> EnharmonicPreference -> Bool)
-> Eq EnharmonicPreference
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EnharmonicPreference -> EnharmonicPreference -> Bool
== :: EnharmonicPreference -> EnharmonicPreference -> Bool
$c/= :: EnharmonicPreference -> EnharmonicPreference -> Bool
/= :: EnharmonicPreference -> EnharmonicPreference -> Bool
Eq, Int -> EnharmonicPreference -> ShowS
[EnharmonicPreference] -> ShowS
EnharmonicPreference -> String
(Int -> EnharmonicPreference -> ShowS)
-> (EnharmonicPreference -> String)
-> ([EnharmonicPreference] -> ShowS)
-> Show EnharmonicPreference
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EnharmonicPreference -> ShowS
showsPrec :: Int -> EnharmonicPreference -> ShowS
$cshow :: EnharmonicPreference -> String
show :: EnharmonicPreference -> String
$cshowList :: [EnharmonicPreference] -> ShowS
showList :: [EnharmonicPreference] -> ShowS
Show)

-- |Get the natural enharmonic preference for a pitch class.
-- C (0) is ambiguous and should be handled specially.
-- F#/Gb (6) is always treated as sharp (F#).
enharmonicPreference :: PitchClass -> EnharmonicPreference
enharmonicPreference :: PitchClass -> EnharmonicPreference
enharmonicPreference (P Int
0)  = EnharmonicPreference
AmbiguousPref  -- C: ambiguous, adopts context
enharmonicPreference (P Int
1)  = EnharmonicPreference
FlatPref       -- Db
enharmonicPreference (P Int
2)  = EnharmonicPreference
SharpPref      -- D
enharmonicPreference (P Int
3)  = EnharmonicPreference
FlatPref       -- Eb
enharmonicPreference (P Int
4)  = EnharmonicPreference
SharpPref      -- E
enharmonicPreference (P Int
5)  = EnharmonicPreference
FlatPref       -- F
enharmonicPreference (P Int
6)  = EnharmonicPreference
SharpPref      -- F# (tritone treated as sharp)
enharmonicPreference (P Int
7)  = EnharmonicPreference
SharpPref      -- G
enharmonicPreference (P Int
8)  = EnharmonicPreference
FlatPref       -- Ab
enharmonicPreference (P Int
9)  = EnharmonicPreference
SharpPref      -- A
enharmonicPreference (P Int
10) = EnharmonicPreference
FlatPref       -- Bb
enharmonicPreference (P Int
11) = EnharmonicPreference
SharpPref      -- B
enharmonicPreference PitchClass
_      = EnharmonicPreference
FlatPref       -- Fallback (shouldn't occur for mod 12)

-- |Determine enharmonic spelling for posterior root given prior's actual spelling and both pitch classes.
-- 
-- Rules:
-- (1) SAME PITCH CLASS: Always use prior's actual spelling (the root hasn't changed!)
--     - Example: D# → D# keep Sharp, Eb → Eb keep Flat
-- (2) C IS FLEXIBLE: When C is prior or posterior, the OTHER pitch's preference can override
--     - Prior is C + posterior is definite: adopt posterior's preference
--     - Posterior is C + prior is definite: adopt prior's actual spelling
--     - Both C: persist current (no preference to guide)
-- (3) BOTH DEFINITE (different pitch classes): Consensus-based switching
--     a) If prior's actual spelling matches posterior's preference → persist (consensus on choice)
--     b) If both have SAME preference AND it differs from prior's actual → switch (consensus to switch)
--     c) Otherwise: persist prior's actual spelling (disagreement or already aligned)
--
-- Examples:
--   D# → D# (same PC) → persist prior's actual spelling (Sharp or Flat, doesn't matter which)
--   D# (actual Sharp) → E (SharpPref) → both prefer Sharp, actual differs → switch to Sharp!
selectEnharm :: EnharmonicSpelling -> PitchClass -> PitchClass -> EnharmonicSpelling
selectEnharm :: EnharmonicSpelling
-> PitchClass -> PitchClass -> EnharmonicSpelling
selectEnharm EnharmonicSpelling
current PitchClass
prior PitchClass
posterior
  -- (1) Same pitch class: always keep prior's actual spelling
  | PitchClass
prior PitchClass -> PitchClass -> Bool
forall a. Eq a => a -> a -> Bool
== PitchClass
posterior = EnharmonicSpelling
current
selectEnharm EnharmonicSpelling
current PitchClass
prior PitchClass
posterior =
  let priorPref :: EnharmonicPreference
priorPref = PitchClass -> EnharmonicPreference
enharmonicPreference PitchClass
prior
      posteriorPref :: EnharmonicPreference
posteriorPref = PitchClass -> EnharmonicPreference
enharmonicPreference PitchClass
posterior
      -- Check if prior's actual spelling matches posterior's preference
      prior_actual_matches_posterior_pref :: Bool
prior_actual_matches_posterior_pref = case (EnharmonicSpelling
current, EnharmonicPreference
posteriorPref) of
        (EnharmonicSpelling
FlatSpelling, EnharmonicPreference
FlatPref) -> Bool
True
        (EnharmonicSpelling
SharpSpelling, EnharmonicPreference
SharpPref) -> Bool
True
        (EnharmonicSpelling, EnharmonicPreference)
_ -> Bool
False
      -- Check if both prefer the same thing but differ from current
      both_same_pref_differs_from_current :: Bool
both_same_pref_differs_from_current = case (EnharmonicPreference
priorPref, EnharmonicPreference
posteriorPref, EnharmonicSpelling
current) of
        (EnharmonicPreference
FlatPref, EnharmonicPreference
FlatPref, EnharmonicSpelling
SharpSpelling) -> Bool
True    -- Both flat but we're sharp
        (EnharmonicPreference
SharpPref, EnharmonicPreference
SharpPref, EnharmonicSpelling
FlatSpelling) -> Bool
True    -- Both sharp but we're flat
        (EnharmonicPreference, EnharmonicPreference, EnharmonicSpelling)
_ -> Bool
False
  in case (EnharmonicPreference
priorPref, EnharmonicPreference
posteriorPref) of
    -- Prior is C (ambiguous): posterior's definite preference overrides
    (EnharmonicPreference
AmbiguousPref, EnharmonicPreference
FlatPref) -> EnharmonicSpelling
FlatSpelling
    (EnharmonicPreference
AmbiguousPref, EnharmonicPreference
SharpPref) -> EnharmonicSpelling
SharpSpelling
    -- Posterior is C (ambiguous): prior's actual spelling carries through
    (EnharmonicPreference
FlatPref, EnharmonicPreference
AmbiguousPref) -> EnharmonicSpelling
current
    (EnharmonicPreference
SharpPref, EnharmonicPreference
AmbiguousPref) -> EnharmonicSpelling
current
    -- Both C (ambiguous): persist current
    (EnharmonicPreference
AmbiguousPref, EnharmonicPreference
AmbiguousPref) -> EnharmonicSpelling
current
    -- Both definite with same preference
    (EnharmonicPreference
FlatPref, EnharmonicPreference
FlatPref) ->
      if Bool
prior_actual_matches_posterior_pref then EnharmonicSpelling
FlatSpelling
      else if Bool
both_same_pref_differs_from_current then EnharmonicSpelling
FlatSpelling
      else EnharmonicSpelling
current
    (EnharmonicPreference
SharpPref, EnharmonicPreference
SharpPref) ->
      if Bool
prior_actual_matches_posterior_pref then EnharmonicSpelling
SharpSpelling
      else if Bool
both_same_pref_differs_from_current then EnharmonicSpelling
SharpSpelling
      else EnharmonicSpelling
current
    -- Both definite but disagree in preference: persist current (prior's actual spelling)
    (EnharmonicPreference, EnharmonicPreference)
_ -> EnharmonicSpelling
current

-- |Default enharmonic spelling for initial state based on root pitch class.
-- C defaults to flat; all others use their natural preference.
defaultEnharm :: PitchClass -> EnharmonicSpelling
defaultEnharm :: PitchClass -> EnharmonicSpelling
defaultEnharm (P Int
0) = EnharmonicSpelling
FlatSpelling  -- C defaults to flat
defaultEnharm PitchClass
pc = case PitchClass -> EnharmonicPreference
enharmonicPreference PitchClass
pc of
  EnharmonicPreference
FlatPref -> EnharmonicSpelling
FlatSpelling
  EnharmonicPreference
SharpPref -> EnharmonicSpelling
SharpSpelling
  EnharmonicPreference
AmbiguousPref -> EnharmonicSpelling
FlatSpelling  -- Fallback (only C should be ambiguous)

-- |Convert enharmonic spelling to the corresponding preference (for symmetry).
spellingToPreference :: EnharmonicSpelling -> EnharmonicPreference
spellingToPreference :: EnharmonicSpelling -> EnharmonicPreference
spellingToPreference EnharmonicSpelling
FlatSpelling = EnharmonicPreference
FlatPref
spellingToPreference EnharmonicSpelling
SharpSpelling = EnharmonicPreference
SharpPref

-- | Select the spelling function for a given 'EnharmonicSpelling' — 'sharp'
-- or 'flat'. Used to render a pitch class as a note name consistently across a
-- progression, so a single chord grid does not mix @F#@ and @Gb@.
enharmonicFunc :: EnharmonicSpelling -> (PitchClass -> NoteName)
enharmonicFunc :: EnharmonicSpelling -> PitchClass -> NoteName
enharmonicFunc EnharmonicSpelling
SharpSpelling = PitchClass -> NoteName
sharp
enharmonicFunc EnharmonicSpelling
FlatSpelling  = PitchClass -> NoteName
flat

-- |Infer enharmonic spelling from absolute pitches (bass first).
-- Three-layer system:
--   Layer 1: 3-set match — bass matches AND remaining 2 PCs are subset of chord
--   Layer 2: 2-set match — bass matches AND remaining 1 PC is subset of chord
--   Layer 3: Root fallback — defaultEnharm on bass PC
inferSpelling :: [Int] -> EnharmonicSpelling
inferSpelling :: [Int] -> EnharmonicSpelling
inferSpelling [] = EnharmonicSpelling
FlatSpelling
inferSpelling [Int]
pcs =
  let bassNorm :: Int
bassNorm = [Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int]
pcs Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
      restSet :: IntSet
restSet = [Int] -> IntSet
IS.fromList ((Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) ([Int] -> [Int]
forall a. HasCallStack => [a] -> [a]
tail [Int]
pcs))
      tryTable :: IntMap [(IntSet, a)] -> Maybe a
tryTable IntMap [(IntSet, a)]
table = case Int -> IntMap [(IntSet, a)] -> Maybe [(IntSet, a)]
forall a. Int -> IntMap a -> Maybe a
IM.lookup Int
bassNorm IntMap [(IntSet, a)]
table of
        Maybe [(IntSet, a)]
Nothing -> Maybe a
forall a. Maybe a
Nothing
        Just [(IntSet, a)]
entries ->
          [a] -> Maybe a
forall a. [a] -> Maybe a
listToMaybe [a
s | (IntSet
upperSet, a
s) <- [(IntSet, a)]
entries, IntSet
upperSet IntSet -> IntSet -> Bool
`IS.isSubsetOf` IntSet
restSet]
  in EnharmonicSpelling
-> Maybe EnharmonicSpelling -> EnharmonicSpelling
forall a. a -> Maybe a -> a
fromMaybe (PitchClass -> EnharmonicSpelling
defaultEnharm (Int -> PitchClass
mkPitchClass Int
bassNorm))
       (IntMap [(IntSet, EnharmonicSpelling)] -> Maybe EnharmonicSpelling
forall {a}. IntMap [(IntSet, a)] -> Maybe a
tryTable IntMap [(IntSet, EnharmonicSpelling)]
layer1Table Maybe EnharmonicSpelling
-> Maybe EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> IntMap [(IntSet, EnharmonicSpelling)] -> Maybe EnharmonicSpelling
forall {a}. IntMap [(IntSet, a)] -> Maybe a
tryTable IntMap [(IntSet, EnharmonicSpelling)]
layer2Table)

-- Layer 1: 3-set rules (bass PC → [(set of required upper PCs, spelling)])
-- Covers triads (maj\/min\/sus4\/dim\/aug) in all inversions,
-- plus maj7\/min7 omit-5 and omit-3 in all inversions.
layer1Table :: IM.IntMap [(IS.IntSet, EnharmonicSpelling)]
layer1Table :: IntMap [(IntSet, EnharmonicSpelling)]
layer1Table = ([(IntSet, EnharmonicSpelling)]
 -> [(IntSet, EnharmonicSpelling)]
 -> [(IntSet, EnharmonicSpelling)])
-> [(Int, [(IntSet, EnharmonicSpelling)])]
-> IntMap [(IntSet, EnharmonicSpelling)]
forall a. (a -> a -> a) -> [(Int, a)] -> IntMap a
IM.fromListWith [(IntSet, EnharmonicSpelling)]
-> [(IntSet, EnharmonicSpelling)] -> [(IntSet, EnharmonicSpelling)]
forall a. [a] -> [a] -> [a]
(++) ([(Int, [(IntSet, EnharmonicSpelling)])]
 -> IntMap [(IntSet, EnharmonicSpelling)])
-> [(Int, [(IntSet, EnharmonicSpelling)])]
-> IntMap [(IntSet, EnharmonicSpelling)]
forall a b. (a -> b) -> a -> b
$ ((Int, [Int], EnharmonicSpelling)
 -> [(Int, [(IntSet, EnharmonicSpelling)])])
-> [(Int, [Int], EnharmonicSpelling)]
-> [(Int, [(IntSet, EnharmonicSpelling)])]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Int, [Int], EnharmonicSpelling)
-> [(Int, [(IntSet, EnharmonicSpelling)])]
forall {a} {b}. (a, [Int], b) -> [(a, [(IntSet, b)])]
expandRoot
  --             bass offsets from root   spelling
  -- Root position major
  [ Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
4, Int
7]   EnharmonicSpelling
FlatSpelling    -- C maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
5, Int
8]   EnharmonicSpelling
FlatSpelling    -- Db maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
6, Int
9]   EnharmonicSpelling
SharpSpelling   -- D maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
7, Int
10]  EnharmonicSpelling
FlatSpelling    -- Eb maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
8, Int
11]  EnharmonicSpelling
SharpSpelling   -- E maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
9, Int
0]   EnharmonicSpelling
FlatSpelling    -- F maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
10, Int
1]  EnharmonicSpelling
SharpSpelling   -- F# maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
11, Int
2]  EnharmonicSpelling
SharpSpelling   -- G maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
0, Int
3]   EnharmonicSpelling
FlatSpelling    -- Ab maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
1, Int
4]   EnharmonicSpelling
SharpSpelling   -- A maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
2, Int
5]   EnharmonicSpelling
FlatSpelling    -- Bb maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
3, Int
6]   EnharmonicSpelling
SharpSpelling   -- B maj
  -- 1st inversion major
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
7, Int
0]   EnharmonicSpelling
FlatSpelling    -- C maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
8, Int
1]   EnharmonicSpelling
FlatSpelling    -- Db maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
9, Int
2]   EnharmonicSpelling
SharpSpelling   -- D maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
10, Int
3]  EnharmonicSpelling
FlatSpelling    -- Eb maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
11, Int
4]  EnharmonicSpelling
SharpSpelling   -- E maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
0, Int
5]   EnharmonicSpelling
FlatSpelling    -- F maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
1, Int
6]   EnharmonicSpelling
SharpSpelling   -- F# maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
2, Int
7]   EnharmonicSpelling
SharpSpelling   -- G maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
3, Int
8]   EnharmonicSpelling
FlatSpelling    -- Ab maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
4, Int
9]   EnharmonicSpelling
SharpSpelling   -- A maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
5, Int
10]  EnharmonicSpelling
FlatSpelling    -- Bb maj 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
6, Int
11]  EnharmonicSpelling
SharpSpelling   -- B maj 1st inv
  -- 2nd inversion major
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
0, Int
4]   EnharmonicSpelling
FlatSpelling    -- C maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
1, Int
5]   EnharmonicSpelling
FlatSpelling    -- Db maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
2, Int
6]   EnharmonicSpelling
SharpSpelling   -- D maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
3, Int
7]   EnharmonicSpelling
FlatSpelling    -- Eb maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
4, Int
8]   EnharmonicSpelling
SharpSpelling   -- E maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
5, Int
9]   EnharmonicSpelling
FlatSpelling    -- F maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
6, Int
10]  EnharmonicSpelling
SharpSpelling   -- F# maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
7, Int
11]  EnharmonicSpelling
SharpSpelling   -- G maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
8, Int
0]   EnharmonicSpelling
FlatSpelling    -- Ab maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
9, Int
1]   EnharmonicSpelling
SharpSpelling   -- A maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
10, Int
2]  EnharmonicSpelling
FlatSpelling    -- Bb maj 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
11, Int
3]  EnharmonicSpelling
SharpSpelling   -- B maj 2nd inv
  -- Root position minor
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
3, Int
7]   EnharmonicSpelling
FlatSpelling    -- C min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
4, Int
8]   EnharmonicSpelling
SharpSpelling   -- C# min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
5, Int
9]   EnharmonicSpelling
FlatSpelling    -- D min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
6, Int
10]  EnharmonicSpelling
FlatSpelling    -- Eb min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
7, Int
11]  EnharmonicSpelling
SharpSpelling   -- E min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
8, Int
0]   EnharmonicSpelling
FlatSpelling    -- F min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
9, Int
1]   EnharmonicSpelling
SharpSpelling   -- F# min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
10, Int
2]  EnharmonicSpelling
FlatSpelling    -- G min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
11, Int
3]  EnharmonicSpelling
SharpSpelling   -- G# min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
0, Int
4]   EnharmonicSpelling
FlatSpelling    -- A min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
1, Int
5]   EnharmonicSpelling
FlatSpelling    -- Bb min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
2, Int
6]   EnharmonicSpelling
SharpSpelling   -- B min
  -- 1st inversion minor
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
7, Int
0]   EnharmonicSpelling
FlatSpelling    -- C min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
8, Int
1]   EnharmonicSpelling
SharpSpelling   -- C# min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
9, Int
2]   EnharmonicSpelling
FlatSpelling    -- D min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
10, Int
3]  EnharmonicSpelling
FlatSpelling    -- Eb min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
11, Int
4]  EnharmonicSpelling
SharpSpelling   -- E min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
0, Int
5]   EnharmonicSpelling
FlatSpelling    -- F min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
1, Int
6]   EnharmonicSpelling
SharpSpelling   -- F# min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
2, Int
7]   EnharmonicSpelling
FlatSpelling    -- G min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
3, Int
8]   EnharmonicSpelling
SharpSpelling   -- G# min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
4, Int
9]   EnharmonicSpelling
FlatSpelling    -- A min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
5, Int
10]  EnharmonicSpelling
FlatSpelling    -- Bb min 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
6, Int
11]  EnharmonicSpelling
SharpSpelling   -- B min 1st inv
  -- 2nd inversion minor
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
0, Int
3]   EnharmonicSpelling
FlatSpelling    -- C min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
1, Int
4]   EnharmonicSpelling
SharpSpelling   -- C# min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
2, Int
5]   EnharmonicSpelling
FlatSpelling    -- D min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
3, Int
6]   EnharmonicSpelling
FlatSpelling    -- Eb min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
4, Int
7]   EnharmonicSpelling
SharpSpelling   -- E min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
5, Int
8]   EnharmonicSpelling
FlatSpelling    -- F min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
6, Int
9]   EnharmonicSpelling
SharpSpelling   -- F# min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
7, Int
10]  EnharmonicSpelling
FlatSpelling    -- G min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
8, Int
11]  EnharmonicSpelling
SharpSpelling   -- G# min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
9, Int
0]   EnharmonicSpelling
FlatSpelling    -- A min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
10, Int
1]  EnharmonicSpelling
FlatSpelling    -- Bb min 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
11, Int
2]  EnharmonicSpelling
SharpSpelling   -- B min 2nd inv
  -- Root position sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
5, Int
7]   EnharmonicSpelling
FlatSpelling    -- C sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
6, Int
8]   EnharmonicSpelling
FlatSpelling    -- Db sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
7, Int
9]   EnharmonicSpelling
SharpSpelling   -- D sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
8, Int
10]  EnharmonicSpelling
FlatSpelling    -- Eb sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
9, Int
11]  EnharmonicSpelling
SharpSpelling   -- E sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
10, Int
0]  EnharmonicSpelling
FlatSpelling    -- F sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
11, Int
1]  EnharmonicSpelling
SharpSpelling   -- F# sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
0, Int
2]   EnharmonicSpelling
SharpSpelling   -- G sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
1, Int
3]   EnharmonicSpelling
FlatSpelling    -- Ab sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
2, Int
4]   EnharmonicSpelling
SharpSpelling   -- A sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
3, Int
5]   EnharmonicSpelling
FlatSpelling    -- Bb sus4
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
4, Int
6]   EnharmonicSpelling
SharpSpelling   -- B sus4
  -- Root position sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
7, Int
0]   EnharmonicSpelling
FlatSpelling    -- F sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
8, Int
1]   EnharmonicSpelling
FlatSpelling    -- Gb sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
9, Int
2]   EnharmonicSpelling
SharpSpelling   -- G sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
10, Int
3]  EnharmonicSpelling
FlatSpelling    -- Ab sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
11, Int
4]  EnharmonicSpelling
SharpSpelling   -- A sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
0, Int
5]   EnharmonicSpelling
FlatSpelling    -- Bb sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
1, Int
6]   EnharmonicSpelling
SharpSpelling   -- B sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
2, Int
7]   EnharmonicSpelling
SharpSpelling   -- C sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
3, Int
8]   EnharmonicSpelling
FlatSpelling    -- Db sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
4, Int
9]   EnharmonicSpelling
SharpSpelling   -- D sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
5, Int
10]  EnharmonicSpelling
FlatSpelling    -- Eb sus2
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
6, Int
11]  EnharmonicSpelling
SharpSpelling   -- E sus2
  -- Root position 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
0, Int
5]   EnharmonicSpelling
FlatSpelling    -- G 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
1, Int
6]   EnharmonicSpelling
FlatSpelling    -- Ab 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
2, Int
7]   EnharmonicSpelling
SharpSpelling   -- A 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
3, Int
8]   EnharmonicSpelling
FlatSpelling    -- Bb 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
4, Int
9]   EnharmonicSpelling
SharpSpelling   -- B 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
5, Int
10]  EnharmonicSpelling
FlatSpelling    -- C 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
6, Int
11]  EnharmonicSpelling
SharpSpelling   -- Db 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
7, Int
0]   EnharmonicSpelling
SharpSpelling   -- D 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
8, Int
1]   EnharmonicSpelling
FlatSpelling    -- Eb 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
9, Int
2]   EnharmonicSpelling
SharpSpelling   -- E 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
10, Int
3]  EnharmonicSpelling
FlatSpelling    -- F 7sus4no5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
11, Int
4]  EnharmonicSpelling
SharpSpelling   -- Gb 7sus4no5
  -- Root position dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
3, Int
6]   EnharmonicSpelling
FlatSpelling    -- C dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
4, Int
7]   EnharmonicSpelling
SharpSpelling   -- C# dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
5, Int
8]   EnharmonicSpelling
FlatSpelling    -- D dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
6, Int
9]   EnharmonicSpelling
SharpSpelling   -- Eb dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
7, Int
10]  EnharmonicSpelling
FlatSpelling    -- E dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
8, Int
11]  EnharmonicSpelling
FlatSpelling    -- F dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
9, Int
0]   EnharmonicSpelling
SharpSpelling   -- F# dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
10, Int
1]  EnharmonicSpelling
FlatSpelling    -- G dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
11, Int
2]  EnharmonicSpelling
SharpSpelling   -- G# dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
0, Int
3]   EnharmonicSpelling
FlatSpelling    -- A dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
1, Int
4]   EnharmonicSpelling
SharpSpelling   -- Bb dim
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
2, Int
5]   EnharmonicSpelling
FlatSpelling    -- B dim
  -- Root position aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
4, Int
8]   EnharmonicSpelling
FlatSpelling    -- C aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
5, Int
9]   EnharmonicSpelling
SharpSpelling   -- C# aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
6, Int
10]  EnharmonicSpelling
FlatSpelling    -- D aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
7, Int
11]  EnharmonicSpelling
SharpSpelling   -- Eb aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
8, Int
0]   EnharmonicSpelling
FlatSpelling    -- E aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
9, Int
1]   EnharmonicSpelling
FlatSpelling    -- F aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
10, Int
2]  EnharmonicSpelling
SharpSpelling   -- F# aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
11, Int
3]  EnharmonicSpelling
FlatSpelling    -- G aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
0, Int
4]   EnharmonicSpelling
SharpSpelling   -- G# aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
1, Int
5]   EnharmonicSpelling
FlatSpelling    -- A aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
2, Int
6]   EnharmonicSpelling
FlatSpelling    -- Bb aug
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
3, Int
7]   EnharmonicSpelling
SharpSpelling   -- B aug
  -- Root position maj7 omit 5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
4, Int
11]  EnharmonicSpelling
FlatSpelling    -- C maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
5, Int
0]   EnharmonicSpelling
FlatSpelling    -- Db maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
6, Int
1]   EnharmonicSpelling
SharpSpelling   -- D maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
7, Int
2]   EnharmonicSpelling
FlatSpelling    -- Eb maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
8, Int
3]   EnharmonicSpelling
SharpSpelling   -- E maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
9, Int
4]   EnharmonicSpelling
FlatSpelling    -- F maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
10, Int
5]  EnharmonicSpelling
SharpSpelling   -- F# maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
11, Int
6]  EnharmonicSpelling
SharpSpelling   -- G maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
0, Int
7]   EnharmonicSpelling
FlatSpelling    -- Ab maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
1, Int
8]   EnharmonicSpelling
SharpSpelling   -- A maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
2, Int
9]   EnharmonicSpelling
FlatSpelling    -- Bb maj7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
3, Int
10]  EnharmonicSpelling
SharpSpelling   -- B maj7o5
  -- 1st inversion maj7 omit 5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
11, Int
0]  EnharmonicSpelling
FlatSpelling    -- C maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
0, Int
1]   EnharmonicSpelling
FlatSpelling    -- Db maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
1, Int
2]   EnharmonicSpelling
SharpSpelling   -- D maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
2, Int
3]   EnharmonicSpelling
FlatSpelling    -- Eb maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
3, Int
4]   EnharmonicSpelling
SharpSpelling   -- E maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
4, Int
5]   EnharmonicSpelling
FlatSpelling    -- F maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
5, Int
6]   EnharmonicSpelling
SharpSpelling   -- F# maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
6, Int
7]   EnharmonicSpelling
SharpSpelling   -- G maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
7, Int
8]   EnharmonicSpelling
FlatSpelling    -- Ab maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
8, Int
9]   EnharmonicSpelling
SharpSpelling   -- A maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
9, Int
10]  EnharmonicSpelling
FlatSpelling    -- Bb maj7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
10, Int
11] EnharmonicSpelling
SharpSpelling   -- B maj7o5 1st inv
  -- 2nd inversion maj7 omit 5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
0, Int
4]   EnharmonicSpelling
FlatSpelling    -- C maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
1, Int
5]   EnharmonicSpelling
FlatSpelling    -- Db maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
2, Int
6]   EnharmonicSpelling
SharpSpelling   -- D maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
3, Int
7]   EnharmonicSpelling
FlatSpelling    -- Eb maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
4, Int
8]   EnharmonicSpelling
SharpSpelling   -- E maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
5, Int
9]   EnharmonicSpelling
FlatSpelling    -- F maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
6, Int
10]  EnharmonicSpelling
SharpSpelling   -- F# maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
7, Int
11]  EnharmonicSpelling
SharpSpelling   -- G maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
8, Int
0]   EnharmonicSpelling
FlatSpelling    -- Ab maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
9, Int
1]   EnharmonicSpelling
SharpSpelling   -- A maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
10, Int
2]  EnharmonicSpelling
FlatSpelling    -- Bb maj7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
11, Int
3]  EnharmonicSpelling
SharpSpelling   -- B maj7o5 2nd inv
  -- Root position maj7 omit 3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
7, Int
11]  EnharmonicSpelling
FlatSpelling    -- C maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
8, Int
0]   EnharmonicSpelling
FlatSpelling    -- Db maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
9, Int
1]   EnharmonicSpelling
SharpSpelling   -- D maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
10, Int
2]  EnharmonicSpelling
FlatSpelling    -- Eb maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
11, Int
3]  EnharmonicSpelling
SharpSpelling   -- E maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
0, Int
4]   EnharmonicSpelling
FlatSpelling    -- F maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
1, Int
5]   EnharmonicSpelling
SharpSpelling   -- F# maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
2, Int
6]   EnharmonicSpelling
SharpSpelling   -- G maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
3, Int
7]   EnharmonicSpelling
FlatSpelling    -- Ab maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
4, Int
8]   EnharmonicSpelling
SharpSpelling   -- A maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
5, Int
9]   EnharmonicSpelling
FlatSpelling    -- Bb maj7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
6, Int
10]  EnharmonicSpelling
SharpSpelling   -- B maj7o3
  -- 1st inversion maj7 omit 3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
11, Int
0]  EnharmonicSpelling
FlatSpelling    -- C maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
0, Int
1]   EnharmonicSpelling
FlatSpelling    -- Db maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
1, Int
2]   EnharmonicSpelling
SharpSpelling   -- D maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
2, Int
3]   EnharmonicSpelling
FlatSpelling    -- Eb maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
3, Int
4]   EnharmonicSpelling
SharpSpelling   -- E maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
4, Int
5]   EnharmonicSpelling
FlatSpelling    -- F maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
5, Int
6]   EnharmonicSpelling
SharpSpelling   -- F# maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
6, Int
7]   EnharmonicSpelling
SharpSpelling   -- G maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
7, Int
8]   EnharmonicSpelling
FlatSpelling    -- Ab maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
8, Int
9]   EnharmonicSpelling
SharpSpelling   -- A maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
9, Int
10]  EnharmonicSpelling
FlatSpelling    -- Bb maj7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
10, Int
11] EnharmonicSpelling
SharpSpelling   -- B maj7o3 1st inv
  -- 2nd inversion maj7 omit 3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
0, Int
7]   EnharmonicSpelling
FlatSpelling    -- C maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
1, Int
8]   EnharmonicSpelling
FlatSpelling    -- Db maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
2, Int
9]   EnharmonicSpelling
SharpSpelling   -- D maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
3, Int
10]  EnharmonicSpelling
FlatSpelling    -- Eb maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
4, Int
11]  EnharmonicSpelling
SharpSpelling   -- E maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
5, Int
0]   EnharmonicSpelling
FlatSpelling    -- F maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
6, Int
1]   EnharmonicSpelling
SharpSpelling   -- F# maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
7, Int
2]   EnharmonicSpelling
SharpSpelling   -- G maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
8, Int
3]   EnharmonicSpelling
FlatSpelling    -- Ab maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
9, Int
4]   EnharmonicSpelling
SharpSpelling   -- A maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
10, Int
5]  EnharmonicSpelling
FlatSpelling    -- Bb maj7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
11, Int
6]  EnharmonicSpelling
SharpSpelling   -- B maj7o3 2nd inv
  -- Root position min7 omit 5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
3, Int
10]  EnharmonicSpelling
FlatSpelling    -- C min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
4, Int
11]  EnharmonicSpelling
SharpSpelling   -- C# min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
5, Int
0]   EnharmonicSpelling
FlatSpelling    -- D min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
6, Int
1]   EnharmonicSpelling
FlatSpelling    -- Eb min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
7, Int
2]   EnharmonicSpelling
SharpSpelling   -- E min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
8, Int
3]   EnharmonicSpelling
FlatSpelling    -- F min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
9, Int
4]   EnharmonicSpelling
SharpSpelling   -- F# min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
10, Int
5]  EnharmonicSpelling
FlatSpelling    -- G min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
11, Int
6]  EnharmonicSpelling
SharpSpelling   -- G# min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
0, Int
7]   EnharmonicSpelling
FlatSpelling    -- A min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
1, Int
8]   EnharmonicSpelling
FlatSpelling    -- Bb min7o5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
2, Int
9]   EnharmonicSpelling
SharpSpelling   -- B min7o5
  -- 1st inversion min7 omit 5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
10, Int
0]  EnharmonicSpelling
FlatSpelling    -- C min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
11, Int
1]  EnharmonicSpelling
SharpSpelling   -- C# min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
0, Int
2]   EnharmonicSpelling
FlatSpelling    -- D min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
1, Int
3]   EnharmonicSpelling
FlatSpelling    -- Eb min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
2, Int
4]   EnharmonicSpelling
SharpSpelling   -- E min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
3, Int
5]   EnharmonicSpelling
FlatSpelling    -- F min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
4, Int
6]   EnharmonicSpelling
SharpSpelling   -- F# min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
5, Int
7]   EnharmonicSpelling
FlatSpelling    -- G min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
6, Int
8]   EnharmonicSpelling
SharpSpelling   -- G# min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
7, Int
9]   EnharmonicSpelling
FlatSpelling    -- A min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
8, Int
10]  EnharmonicSpelling
FlatSpelling    -- Bb min7o5 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
9, Int
11]  EnharmonicSpelling
SharpSpelling   -- B min7o5 1st inv
  -- 2nd inversion min7 omit 5
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
0, Int
3]   EnharmonicSpelling
FlatSpelling    -- C min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
1, Int
4]   EnharmonicSpelling
SharpSpelling   -- C# min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
2, Int
5]   EnharmonicSpelling
FlatSpelling    -- D min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
3, Int
6]   EnharmonicSpelling
FlatSpelling    -- Eb min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
4, Int
7]   EnharmonicSpelling
SharpSpelling   -- E min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
5, Int
8]   EnharmonicSpelling
FlatSpelling    -- F min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
6, Int
9]   EnharmonicSpelling
SharpSpelling   -- F# min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
7, Int
10]  EnharmonicSpelling
FlatSpelling    -- G min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
8, Int
11]  EnharmonicSpelling
SharpSpelling   -- G# min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
9, Int
0]   EnharmonicSpelling
FlatSpelling    -- A min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
10, Int
1]  EnharmonicSpelling
FlatSpelling    -- Bb min7o5 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
11, Int
2]  EnharmonicSpelling
SharpSpelling   -- B min7o5 2nd inv
  -- Root position min7 omit 3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
7, Int
10]  EnharmonicSpelling
FlatSpelling    -- C min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
8, Int
11]  EnharmonicSpelling
SharpSpelling   -- C# min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
9, Int
0]   EnharmonicSpelling
FlatSpelling    -- D min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
10, Int
1]  EnharmonicSpelling
FlatSpelling    -- Eb min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
11, Int
2]  EnharmonicSpelling
SharpSpelling   -- E min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
0, Int
3]   EnharmonicSpelling
FlatSpelling    -- F min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
1, Int
4]   EnharmonicSpelling
SharpSpelling   -- F# min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
2, Int
5]   EnharmonicSpelling
FlatSpelling    -- G min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
3, Int
6]   EnharmonicSpelling
SharpSpelling   -- G# min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
4, Int
7]   EnharmonicSpelling
FlatSpelling    -- A min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
5, Int
8]   EnharmonicSpelling
FlatSpelling    -- Bb min7o3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
6, Int
9]   EnharmonicSpelling
SharpSpelling   -- B min7o3
  -- 1st inversion min7 omit 3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
10, Int
0]  EnharmonicSpelling
FlatSpelling    -- C min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
11, Int
1]  EnharmonicSpelling
SharpSpelling   -- C# min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
0, Int
2]   EnharmonicSpelling
FlatSpelling    -- D min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
1, Int
3]   EnharmonicSpelling
FlatSpelling    -- Eb min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
2, Int
4]   EnharmonicSpelling
SharpSpelling   -- E min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
3, Int
5]   EnharmonicSpelling
FlatSpelling    -- F min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
4, Int
6]   EnharmonicSpelling
SharpSpelling   -- F# min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
5, Int
7]   EnharmonicSpelling
FlatSpelling    -- G min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
6, Int
8]   EnharmonicSpelling
SharpSpelling   -- G# min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
7, Int
9]   EnharmonicSpelling
FlatSpelling    -- A min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
8, Int
10]  EnharmonicSpelling
FlatSpelling    -- Bb min7o3 1st inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
9, Int
11]  EnharmonicSpelling
SharpSpelling   -- B min7o3 1st inv
  -- 2nd inversion min7 omit 3
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
0, Int
7]   EnharmonicSpelling
FlatSpelling    -- C min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
1, Int
8]   EnharmonicSpelling
SharpSpelling   -- C# min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
2, Int
9]   EnharmonicSpelling
FlatSpelling    -- D min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
3, Int
10]  EnharmonicSpelling
FlatSpelling    -- Eb min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
4, Int
11]  EnharmonicSpelling
SharpSpelling   -- E min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
5, Int
0]   EnharmonicSpelling
FlatSpelling    -- F min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
6, Int
1]   EnharmonicSpelling
SharpSpelling   -- F# min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
7, Int
2]   EnharmonicSpelling
FlatSpelling    -- G min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
8, Int
3]   EnharmonicSpelling
SharpSpelling   -- G# min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
9, Int
4]   EnharmonicSpelling
FlatSpelling    -- A min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
10, Int
5]  EnharmonicSpelling
FlatSpelling    -- Bb min7o3 2nd inv
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
11, Int
6]  EnharmonicSpelling
SharpSpelling   -- B min7o3 2nd inv
  ]
  where
    rootEntry :: a -> b -> c -> (a, b, c)
rootEntry a
bass b
upper c
s = (a
bass, b
upper, c
s)
    expandRoot :: (a, [Int], b) -> [(a, [(IntSet, b)])]
expandRoot (a
bass, [Int]
upper, b
s) = [(a
bass, [([Int] -> IntSet
IS.fromList [Int]
upper, b
s)])]

-- Layer 2: 2-set rules (bass PC → [(set of required upper PC, spelling)])
-- Covers major and minor double stops as intermediate fallback.
layer2Table :: IM.IntMap [(IS.IntSet, EnharmonicSpelling)]
layer2Table :: IntMap [(IntSet, EnharmonicSpelling)]
layer2Table = ([(IntSet, EnharmonicSpelling)]
 -> [(IntSet, EnharmonicSpelling)]
 -> [(IntSet, EnharmonicSpelling)])
-> [(Int, [(IntSet, EnharmonicSpelling)])]
-> IntMap [(IntSet, EnharmonicSpelling)]
forall a. (a -> a -> a) -> [(Int, a)] -> IntMap a
IM.fromListWith [(IntSet, EnharmonicSpelling)]
-> [(IntSet, EnharmonicSpelling)] -> [(IntSet, EnharmonicSpelling)]
forall a. [a] -> [a] -> [a]
(++) ([(Int, [(IntSet, EnharmonicSpelling)])]
 -> IntMap [(IntSet, EnharmonicSpelling)])
-> [(Int, [(IntSet, EnharmonicSpelling)])]
-> IntMap [(IntSet, EnharmonicSpelling)]
forall a b. (a -> b) -> a -> b
$ ((Int, [Int], EnharmonicSpelling)
 -> [(Int, [(IntSet, EnharmonicSpelling)])])
-> [(Int, [Int], EnharmonicSpelling)]
-> [(Int, [(IntSet, EnharmonicSpelling)])]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Int, [Int], EnharmonicSpelling)
-> [(Int, [(IntSet, EnharmonicSpelling)])]
forall {a} {b}. (a, [Int], b) -> [(a, [(IntSet, b)])]
expandRoot
  -- Major double stop (root + major 3rd)
  [ Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
4]   EnharmonicSpelling
FlatSpelling    -- C maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
5]   EnharmonicSpelling
FlatSpelling    -- Db maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
6]   EnharmonicSpelling
SharpSpelling   -- D maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
7]   EnharmonicSpelling
FlatSpelling    -- Eb maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
8]   EnharmonicSpelling
SharpSpelling   -- E maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
9]   EnharmonicSpelling
FlatSpelling    -- F maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
10]  EnharmonicSpelling
SharpSpelling   -- F# maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
11]  EnharmonicSpelling
SharpSpelling   -- G maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
0]   EnharmonicSpelling
FlatSpelling    -- Ab maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
1]   EnharmonicSpelling
SharpSpelling   -- A maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
2]   EnharmonicSpelling
FlatSpelling    -- Bb maj
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
3]   EnharmonicSpelling
SharpSpelling   -- B maj
  -- Minor double stop (root + minor 3rd)
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
0 [Int
3]   EnharmonicSpelling
FlatSpelling    -- C min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
1 [Int
4]   EnharmonicSpelling
SharpSpelling   -- C# min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
2 [Int
5]   EnharmonicSpelling
FlatSpelling    -- D min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
3 [Int
6]   EnharmonicSpelling
FlatSpelling    -- Eb min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
4 [Int
7]   EnharmonicSpelling
SharpSpelling   -- E min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
5 [Int
8]   EnharmonicSpelling
FlatSpelling    -- F min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
6 [Int
9]   EnharmonicSpelling
SharpSpelling   -- F# min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
7 [Int
10]  EnharmonicSpelling
FlatSpelling    -- G min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
8 [Int
11]  EnharmonicSpelling
SharpSpelling   -- G# min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry  Int
9 [Int
0]   EnharmonicSpelling
FlatSpelling    -- A min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
10 [Int
1]   EnharmonicSpelling
FlatSpelling    -- Bb min
  , Int
-> [Int] -> EnharmonicSpelling -> (Int, [Int], EnharmonicSpelling)
forall {a} {b} {c}. a -> b -> c -> (a, b, c)
rootEntry Int
11 [Int
2]   EnharmonicSpelling
SharpSpelling   -- B min
  ]
  where
    rootEntry :: a -> b -> c -> (a, b, c)
rootEntry a
bass b
upper c
s = (a
bass, b
upper, c
s)
    expandRoot :: (a, [Int], b) -> [(a, [(IntSet, b)])]
expandRoot (a
bass, [Int]
upper, b
s) = [(a
bass, [([Int] -> IntSet
IS.fromList [Int]
upper, b
s)])]

-- |Detect if a NoteName carries an explicit sharp\/flat preference.
-- Sharp variants (C', D', F', G', A') → Just SharpSpelling
-- Flat variants (Db, Eb, Gb, Ab, Bb) → Just FlatSpelling
-- Natural notes (C, D, E, F, G, A, B) → Nothing (use inference)
noteNameImpliesSpelling :: NoteName -> Maybe EnharmonicSpelling
noteNameImpliesSpelling :: NoteName -> Maybe EnharmonicSpelling
noteNameImpliesSpelling NoteName
C' = EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. a -> Maybe a
Just EnharmonicSpelling
SharpSpelling
noteNameImpliesSpelling NoteName
D' = EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. a -> Maybe a
Just EnharmonicSpelling
SharpSpelling
noteNameImpliesSpelling NoteName
F' = EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. a -> Maybe a
Just EnharmonicSpelling
SharpSpelling
noteNameImpliesSpelling NoteName
G' = EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. a -> Maybe a
Just EnharmonicSpelling
SharpSpelling
noteNameImpliesSpelling NoteName
A' = EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. a -> Maybe a
Just EnharmonicSpelling
SharpSpelling
noteNameImpliesSpelling NoteName
Db = EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. a -> Maybe a
Just EnharmonicSpelling
FlatSpelling
noteNameImpliesSpelling NoteName
Eb = EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. a -> Maybe a
Just EnharmonicSpelling
FlatSpelling
noteNameImpliesSpelling NoteName
Gb = EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. a -> Maybe a
Just EnharmonicSpelling
FlatSpelling
noteNameImpliesSpelling NoteName
Ab = EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. a -> Maybe a
Just EnharmonicSpelling
FlatSpelling
noteNameImpliesSpelling NoteName
Bb = EnharmonicSpelling -> Maybe EnharmonicSpelling
forall a. a -> Maybe a
Just EnharmonicSpelling
FlatSpelling
noteNameImpliesSpelling NoteName
_  = Maybe EnharmonicSpelling
forall a. Maybe a
Nothing

-- |Patterns that are enharmonically ambiguous mid-progression.
-- Only min7o3 (root + P5 + m7) at roots where major\/minor triads differ in spelling.
-- Roots 1 (Db\/C#), 2 (D), 7 (G), 8 (Ab\/G#), 9 (A): major 3rd → one spelling, minor 3rd → different.
-- Roots 0, 3, 4, 5, 6, 10, 11: same spelling regardless of 3rd → NOT ambiguous.
ambiguousPatterns :: IM.IntMap [IS.IntSet]
ambiguousPatterns :: IntMap [IntSet]
ambiguousPatterns = ([IntSet] -> [IntSet] -> [IntSet])
-> [(Int, [IntSet])] -> IntMap [IntSet]
forall a. (a -> a -> a) -> [(Int, a)] -> IntMap a
IM.fromListWith [IntSet] -> [IntSet] -> [IntSet]
forall a. [a] -> [a] -> [a]
(++)
  [ (Int
bass Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12, [[Int] -> IntSet
IS.fromList ((Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) [Int]
uppers)])
  | Int
root <- [Int
1, Int
2, Int
7, Int
8, Int
9]
  , (Int
bass, [Int]
uppers) <- Int -> [(Int, [Int])]
forall {a}. Num a => a -> [(a, [a])]
min7o3Inversions Int
root
  ]
  where
    min7o3Inversions :: a -> [(a, [a])]
min7o3Inversions a
r =
      [ (a
r,    [a
ra -> a -> a
forall a. Num a => a -> a -> a
+a
7, a
ra -> a -> a
forall a. Num a => a -> a -> a
+a
10])
      , (a
ra -> a -> a
forall a. Num a => a -> a -> a
+a
7,  [a
ra -> a -> a
forall a. Num a => a -> a -> a
+a
10, a
r])
      , (a
ra -> a -> a
forall a. Num a => a -> a -> a
+a
10, [a
r, a
ra -> a -> a
forall a. Num a => a -> a -> a
+a
7])
      ]

-- |Check if a chord's absolute pitches match an ambiguous pattern.
isAmbiguousPattern :: [Int] -> Bool
isAmbiguousPattern :: [Int] -> Bool
isAmbiguousPattern [] = Bool
False
isAmbiguousPattern [Int]
pcs =
  let bassNorm :: Int
bassNorm = [Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int]
pcs Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
      restSet :: IntSet
restSet = [Int] -> IntSet
IS.fromList ((Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) ([Int] -> [Int]
forall a. HasCallStack => [a] -> [a]
tail [Int]
pcs))
  in case Int -> IntMap [IntSet] -> Maybe [IntSet]
forall a. Int -> IntMap a -> Maybe a
IM.lookup Int
bassNorm IntMap [IntSet]
ambiguousPatterns of
       Maybe [IntSet]
Nothing -> Bool
False
       Just [IntSet]
patterns -> (IntSet -> Bool) -> [IntSet] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (IntSet -> IntSet -> Bool
`IS.isSubsetOf` IntSet
restSet) [IntSet]
patterns

-------------------------------------------------------------------------------
-- Functionality (Chord Quality as String)
-------------------------------------------------------------------------------

-- |Chord quality\/functionality as a string (e.g., "maj", "min7", "dim")
-- Preserved as String for compatibility with legacy naming conventions
type Functionality = String

-- |Derive functionality name from a pitch set using the legacy triad nameFunc
-- This is for TRIADS (exactly 3 pitch classes)
toFunctionality :: [PitchClass] -> Functionality
toFunctionality :: [PitchClass] -> String
toFunctionality [PitchClass]
ps = ([PitchClass] -> [PitchClass]) -> [PitchClass] -> ShowS
nameFuncTriad [PitchClass] -> [PitchClass]
forall {a}. a -> a
zeroFormFn [PitchClass]
ps String
""
  where zeroFormFn :: a -> a
zeroFormFn = a -> a
forall {a}. a -> a
id  -- We expect input already in zero form

-- |Derive functionality name from a pitch set using the chord nameFunc
-- This is for CHORDS (any number of pitch classes, extended harmonies)
toFunctionalityChord :: [PitchClass] -> Functionality
toFunctionalityChord :: [PitchClass] -> String
toFunctionalityChord [PitchClass]
ps = ([PitchClass] -> [PitchClass]) -> [PitchClass] -> ShowS
nameFuncChord [PitchClass] -> [PitchClass]
forall {a}. a -> a
zeroFormFn [PitchClass]
ps String
""
  where zeroFormFn :: a -> a
zeroFormFn = a -> a
forall {a}. a -> a
id  -- We expect input already in zero form

-------------------------------------------------------------------------------
-- Movement (Bass Motion)
-------------------------------------------------------------------------------

-- |Movement represents bass motion by a musical interval
data Movement 
  = Asc PitchClass   -- ^ Ascending by n semitones (1-5)
  | Desc PitchClass  -- ^ Descending by n semitones (1-5)
  | Unison           -- ^ Pedal (no movement)
  | Tritone          -- ^ Movement by 6 semitones
  | Empty            -- ^ Placeholder for invalid\/missing movement
  deriving (Eq Movement
Eq Movement =>
(Movement -> Movement -> Ordering)
-> (Movement -> Movement -> Bool)
-> (Movement -> Movement -> Bool)
-> (Movement -> Movement -> Bool)
-> (Movement -> Movement -> Bool)
-> (Movement -> Movement -> Movement)
-> (Movement -> Movement -> Movement)
-> Ord Movement
Movement -> Movement -> Bool
Movement -> Movement -> Ordering
Movement -> Movement -> Movement
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Movement -> Movement -> Ordering
compare :: Movement -> Movement -> Ordering
$c< :: Movement -> Movement -> Bool
< :: Movement -> Movement -> Bool
$c<= :: Movement -> Movement -> Bool
<= :: Movement -> Movement -> Bool
$c> :: Movement -> Movement -> Bool
> :: Movement -> Movement -> Bool
$c>= :: Movement -> Movement -> Bool
>= :: Movement -> Movement -> Bool
$cmax :: Movement -> Movement -> Movement
max :: Movement -> Movement -> Movement
$cmin :: Movement -> Movement -> Movement
min :: Movement -> Movement -> Movement
Ord, Movement -> Movement -> Bool
(Movement -> Movement -> Bool)
-> (Movement -> Movement -> Bool) -> Eq Movement
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Movement -> Movement -> Bool
== :: Movement -> Movement -> Bool
$c/= :: Movement -> Movement -> Bool
/= :: Movement -> Movement -> Bool
Eq, (forall x. Movement -> Rep Movement x)
-> (forall x. Rep Movement x -> Movement) -> Generic Movement
forall x. Rep Movement x -> Movement
forall x. Movement -> Rep Movement x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Movement -> Rep Movement x
from :: forall x. Movement -> Rep Movement x
$cto :: forall x. Rep Movement x -> Movement
to :: forall x. Rep Movement x -> Movement
Generic)

instance Show Movement where
  show :: Movement -> String
  show :: Movement -> String
show (Asc PitchClass
n)  = String
"asc " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (PitchClass -> Int
unPitchClass PitchClass
n)
  show (Desc PitchClass
n) = String
"desc " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (PitchClass -> Int
unPitchClass PitchClass
n)
  show Movement
Unison   = String
"pedal"
  show Movement
Tritone  = String
"tritone"
  show Movement
Empty    = String
"empty"

instance Read Movement where
  readsPrec :: Int -> ReadS Movement
  readsPrec :: Int -> ReadS Movement
readsPrec Int
_ String
s
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"pedal"   = [(Movement
Unison, String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"asc 1"   = [(PitchClass -> Movement
Asc (Int -> PitchClass
P Int
1), String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"asc 2"   = [(PitchClass -> Movement
Asc (Int -> PitchClass
P Int
2), String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"asc 3"   = [(PitchClass -> Movement
Asc (Int -> PitchClass
P Int
3), String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"asc 4"   = [(PitchClass -> Movement
Asc (Int -> PitchClass
P Int
4), String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"asc 5"   = [(PitchClass -> Movement
Asc (Int -> PitchClass
P Int
5), String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"tritone" = [(Movement
Tritone, String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"desc 5"  = [(PitchClass -> Movement
Desc (Int -> PitchClass
P Int
5), String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"desc 4"  = [(PitchClass -> Movement
Desc (Int -> PitchClass
P Int
4), String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"desc 3"  = [(PitchClass -> Movement
Desc (Int -> PitchClass
P Int
3), String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"desc 2"  = [(PitchClass -> Movement
Desc (Int -> PitchClass
P Int
2), String
"")]
    | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"desc 1"  = [(PitchClass -> Movement
Desc (Int -> PitchClass
P Int
1), String
"")]
    | Bool
otherwise      = [(Movement
Empty, String
"")]

-- |Convert two pitch classes to a Movement (bass motion direction\/distance)
-- Ported from legacy MusicData.hs toMovement
-- 
-- Movement direction is determined by the shorter path around the pitch class circle.
-- Example: C(0) to G(7) = descending by 5 (shorter path is 5 semitones down via P 12)
--          G(7) to C(0) = ascending by 5 (shorter path is 5 semitones up to P 12 ≡ P 0)
toMovement :: PitchClass -> PitchClass -> Movement
toMovement :: PitchClass -> PitchClass -> Movement
toMovement PitchClass
from PitchClass
to
  | Int
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
y           = PitchClass -> Movement
Asc (Int -> PitchClass
P Int
x)    -- shorter path is forwards = ascending
  | Int
y Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
x           = PitchClass -> Movement
Desc (Int -> PitchClass
P Int
y)   -- shorter path is backwards = descending
  | Int
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
&& Int
y Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Movement
Unison
  | Bool
otherwise       = Movement
Tritone
  where
    x :: Int
x = [Int] -> Int
forall a. HasCallStack => [a] -> a
last ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ [Int] -> [Int]
forall {a}. Integral a => [a] -> [a]
zeroFormLegacy [PitchClass -> Int
unPitchClass PitchClass
from, PitchClass -> Int
unPitchClass PitchClass
to]
    y :: Int
y = [Int] -> Int
forall a. HasCallStack => [a] -> a
last ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ [Int] -> [Int]
forall {a}. Integral a => [a] -> [a]
zeroFormLegacy [PitchClass -> Int
unPitchClass PitchClass
to, PitchClass -> Int
unPitchClass PitchClass
from]
    -- Legacy zeroForm: subtract the FIRST element, then sort
    zeroFormLegacy :: [a] -> [a]
zeroFormLegacy (a
h:[a]
hs) = [a] -> [a]
forall a. Ord a => [a] -> [a]
sort ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ (a -> a) -> [a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (\a
n -> (a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
h) a -> a -> a
forall a. Integral a => a -> a -> a
`mod` a
12) (a
ha -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
hs)
    zeroFormLegacy []     = []

-- |Convert Movement back to PitchClass interval
fromMovement :: Movement -> PitchClass
fromMovement :: Movement -> PitchClass
fromMovement (Asc PitchClass
n)  = PitchClass
n
fromMovement (Desc PitchClass
n) = Int -> PitchClass
P (Int
12 Int -> Int -> Int
forall a. Num a => a -> a -> a
- PitchClass -> Int
unPitchClass PitchClass
n)
fromMovement Movement
Unison   = Int -> PitchClass
P Int
0
fromMovement Movement
Tritone  = Int -> PitchClass
P Int
6
fromMovement Movement
Empty    = Int -> PitchClass
P Int
0

-------------------------------------------------------------------------------
-- Abstract Types
-------------------------------------------------------------------------------

-- |A Chord is an abstract pitch structure: root note name, functionality, 
-- and intervals from root (bass first, as integers for register info).
data Chord = Chord 
  { Chord -> NoteName
chordNoteName     :: NoteName
  , Chord -> String
chordFunctionality :: Functionality
  , Chord -> [Integer]
chordIntervals    :: [Integer]
  } deriving (Chord -> Chord -> Bool
(Chord -> Chord -> Bool) -> (Chord -> Chord -> Bool) -> Eq Chord
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Chord -> Chord -> Bool
== :: Chord -> Chord -> Bool
$c/= :: Chord -> Chord -> Bool
/= :: Chord -> Chord -> Bool
Eq, Eq Chord
Eq Chord =>
(Chord -> Chord -> Ordering)
-> (Chord -> Chord -> Bool)
-> (Chord -> Chord -> Bool)
-> (Chord -> Chord -> Bool)
-> (Chord -> Chord -> Bool)
-> (Chord -> Chord -> Chord)
-> (Chord -> Chord -> Chord)
-> Ord Chord
Chord -> Chord -> Bool
Chord -> Chord -> Ordering
Chord -> Chord -> Chord
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Chord -> Chord -> Ordering
compare :: Chord -> Chord -> Ordering
$c< :: Chord -> Chord -> Bool
< :: Chord -> Chord -> Bool
$c<= :: Chord -> Chord -> Bool
<= :: Chord -> Chord -> Bool
$c> :: Chord -> Chord -> Bool
> :: Chord -> Chord -> Bool
$c>= :: Chord -> Chord -> Bool
>= :: Chord -> Chord -> Bool
$cmax :: Chord -> Chord -> Chord
max :: Chord -> Chord -> Chord
$cmin :: Chord -> Chord -> Chord
min :: Chord -> Chord -> Chord
Ord, (forall x. Chord -> Rep Chord x)
-> (forall x. Rep Chord x -> Chord) -> Generic Chord
forall x. Rep Chord x -> Chord
forall x. Chord -> Rep Chord x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Chord -> Rep Chord x
from :: forall x. Chord -> Rep Chord x
$cto :: forall x. Rep Chord x -> Chord
to :: forall x. Rep Chord x -> Chord
Generic)

instance Show Chord where
  show :: Chord -> String
show (Chord NoteName
noteName String
functionality [Integer]
_)
    | String
functionality String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"N/A" = ShowS
forall a. Show a => a -> String
show String
"N/A"
    | Bool
otherwise              = NoteName -> String
forall a. Show a => a -> String
show NoteName
noteName String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"_" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
functionality

-- |A Cadence is a movement type combined with a target chord quality.
-- Abstract: defines "approach by descending 5th to a major chord" without
-- specifying which root pitch.
data Cadence = Cadence 
  { Cadence -> String
cadenceFunctionality :: Functionality
  , Cadence -> Movement
cadenceMovement      :: Movement
  , Cadence -> [PitchClass]
cadenceIntervals     :: [PitchClass]
  } deriving (Cadence -> Cadence -> Bool
(Cadence -> Cadence -> Bool)
-> (Cadence -> Cadence -> Bool) -> Eq Cadence
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Cadence -> Cadence -> Bool
== :: Cadence -> Cadence -> Bool
$c/= :: Cadence -> Cadence -> Bool
/= :: Cadence -> Cadence -> Bool
Eq, Eq Cadence
Eq Cadence =>
(Cadence -> Cadence -> Ordering)
-> (Cadence -> Cadence -> Bool)
-> (Cadence -> Cadence -> Bool)
-> (Cadence -> Cadence -> Bool)
-> (Cadence -> Cadence -> Bool)
-> (Cadence -> Cadence -> Cadence)
-> (Cadence -> Cadence -> Cadence)
-> Ord Cadence
Cadence -> Cadence -> Bool
Cadence -> Cadence -> Ordering
Cadence -> Cadence -> Cadence
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Cadence -> Cadence -> Ordering
compare :: Cadence -> Cadence -> Ordering
$c< :: Cadence -> Cadence -> Bool
< :: Cadence -> Cadence -> Bool
$c<= :: Cadence -> Cadence -> Bool
<= :: Cadence -> Cadence -> Bool
$c> :: Cadence -> Cadence -> Bool
> :: Cadence -> Cadence -> Bool
$c>= :: Cadence -> Cadence -> Bool
>= :: Cadence -> Cadence -> Bool
$cmax :: Cadence -> Cadence -> Cadence
max :: Cadence -> Cadence -> Cadence
$cmin :: Cadence -> Cadence -> Cadence
min :: Cadence -> Cadence -> Cadence
Ord, (forall x. Cadence -> Rep Cadence x)
-> (forall x. Rep Cadence x -> Cadence) -> Generic Cadence
forall x. Rep Cadence x -> Cadence
forall x. Cadence -> Rep Cadence x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Cadence -> Rep Cadence x
from :: forall x. Cadence -> Rep Cadence x
$cto :: forall x. Rep Cadence x -> Cadence
to :: forall x. Rep Cadence x -> Cadence
Generic)

instance Show Cadence where
  show :: Cadence -> String
show (Cadence String
functionality Movement
mvmt [PitchClass]
_) =
    String
"( " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Movement -> String
forall a. Show a => a -> String
show Movement
mvmt String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" -> " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
functionality String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" )"

-------------------------------------------------------------------------------
-- Concrete State Types
-------------------------------------------------------------------------------

-- |A ChordState is a Chord with a concrete root pitch (anchored in pitch space).
data ChordState = ChordState
  { ChordState -> Chord
stateChord :: Chord
  , ChordState -> NoteName
stateRoot  :: NoteName
  } deriving (ChordState -> ChordState -> Bool
(ChordState -> ChordState -> Bool)
-> (ChordState -> ChordState -> Bool) -> Eq ChordState
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ChordState -> ChordState -> Bool
== :: ChordState -> ChordState -> Bool
$c/= :: ChordState -> ChordState -> Bool
/= :: ChordState -> ChordState -> Bool
Eq, (forall x. ChordState -> Rep ChordState x)
-> (forall x. Rep ChordState x -> ChordState) -> Generic ChordState
forall x. Rep ChordState x -> ChordState
forall x. ChordState -> Rep ChordState x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ChordState -> Rep ChordState x
from :: forall x. ChordState -> Rep ChordState x
$cto :: forall x. Rep ChordState x -> ChordState
to :: forall x. Rep ChordState x -> ChordState
Generic)

instance Show ChordState where
  show :: ChordState -> String
show (ChordState Chord
chord NoteName
root) = NoteName -> String
forall a. Show a => a -> String
show NoteName
root String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Chord -> String
forall a. Show a => a -> String
show Chord
chord

-- |A CadenceState is a Cadence with a concrete root pitch and enharmonic spelling.
-- This represents "descend by 5th to G major (flat spelling)" rather than abstract.
-- The enharmonic spelling ensures consistent note naming throughout a progression.
data CadenceState = CadenceState 
  { CadenceState -> Cadence
stateCadence     :: Cadence
  , CadenceState -> NoteName
stateCadenceRoot :: NoteName
  , CadenceState -> EnharmonicSpelling
stateSpelling    :: EnharmonicSpelling
  } deriving (CadenceState -> CadenceState -> Bool
(CadenceState -> CadenceState -> Bool)
-> (CadenceState -> CadenceState -> Bool) -> Eq CadenceState
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CadenceState -> CadenceState -> Bool
== :: CadenceState -> CadenceState -> Bool
$c/= :: CadenceState -> CadenceState -> Bool
/= :: CadenceState -> CadenceState -> Bool
Eq, (forall x. CadenceState -> Rep CadenceState x)
-> (forall x. Rep CadenceState x -> CadenceState)
-> Generic CadenceState
forall x. Rep CadenceState x -> CadenceState
forall x. CadenceState -> Rep CadenceState x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. CadenceState -> Rep CadenceState x
from :: forall x. CadenceState -> Rep CadenceState x
$cto :: forall x. Rep CadenceState x -> CadenceState
to :: forall x. Rep CadenceState x -> CadenceState
Generic)

instance Show CadenceState where
  show :: CadenceState -> String
show (CadenceState Cadence
cadence NoteName
root EnharmonicSpelling
_) =
    String
"( " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Movement -> String
forall a. Show a => a -> String
show (Cadence -> Movement
cadenceMovement Cadence
cadence) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" -> " String -> ShowS
forall a. [a] -> [a] -> [a]
++ 
    NoteName -> String
forall a. Show a => a -> String
show NoteName
root String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"_" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Cadence -> String
cadenceFunctionality Cadence
cadence String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" )"

-------------------------------------------------------------------------------
-- nameFuncTriad: VERBATIM PORT from legacy MusicData.hs (lines 443-479)
-- This function implements the TRIAD naming conventions exactly.
-- Used for exactly 3-pitch structures with inversion detection.
-------------------------------------------------------------------------------

-- |Triad naming function ported VERBATIM from legacy MusicData.hs
-- Takes a form function, pitch classes, and accumulator string.
-- Returns the functionality string (e.g., "maj", "min", "dim", etc.)
nameFuncTriad :: ([PitchClass] -> [PitchClass]) -> [PitchClass] -> String -> String
nameFuncTriad :: ([PitchClass] -> [PitchClass]) -> [PitchClass] -> ShowS
nameFuncTriad [PitchClass] -> [PitchClass]
f [PitchClass]
xs =
  let
    zs :: [Int]
zs = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int) -> (PitchClass -> Int) -> PitchClass -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PitchClass -> Int
unPitchClass (PitchClass -> Int) -> [PitchClass] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [PitchClass] -> [PitchClass]
f [PitchClass]
xs :: [Int]
    chain :: [ShowS]
chain =
      [if (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
4 [Int]
zs Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
3,Int
10,Int
11]) Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
8 [Int]
zs
        then (String
"maj"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
3 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
4 [Int]
zs) Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
6 [Int]
zs
        then (String
"min"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
9 [Int]
zs then (String
"6"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
10 [Int]
zs then (String
"7"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
11 [Int]
zs then (String
"maj7"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
7,Int
8] then (String
"b13"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      -- sus2: has 2, has 5th (7), no 4th (5), no 3rd (3,4)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
2 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
5 [Int]
zs Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
3,Int
4] Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
7 [Int]
zs
        then (String
"sus2"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      -- sus4: has 4th (5), has 5th (7), no 3rd, AND not already sus2 (must have 5, not just 2)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
5 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
2 [Int]
zs Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
3,Int
4] Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
7 [Int]
zs
        then (String
"sus4"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
2,Int
5] then (String
"sus2/4"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
5 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
2 [Int]
zs Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
3,Int
4]
        Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
7 [Int]
zs then (String
"sus2"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
2 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
5 [Int]
zs Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
3,Int
4]
        Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
7 [Int]
zs then (String
"sus4"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
2,Int
3] Bool -> Bool -> Bool
|| (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
2,Int
4]
        then (String
"add9"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
5,Int
3] Bool -> Bool -> Bool
|| (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
5,Int
4]
        then (String
"add11"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
1 [Int]
zs then (String
"b9"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
3,Int
4] then (String
"#9"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
6 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
5 [Int]
zs Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
7,Int
8]
        then (String
"#11"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if ((Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
6 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
7 [Int]
zs) Bool -> Bool -> Bool
|| (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
6 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
8 [Int]
zs))
        Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
3 [Int]
zs Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
7,Int
8]
        then (String
"b5"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if ((Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
8 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
7 [Int]
zs) Bool -> Bool -> Bool
|| (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
8,Int
9])
        Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
4 [Int]
zs then (String
"#5"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
2,Int
3,Int
4,Int
5] then (String
"no3"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
6,Int
7,Int
8] then (String
"no5"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
3,Int
6] then (String
"dim"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
4,Int
8] then (String
"aug"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)]
   in (ShowS -> ShowS -> ShowS) -> ShowS -> [ShowS] -> ShowS
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.) ShowS
forall {a}. a -> a
id [ShowS]
chain

-------------------------------------------------------------------------------
-- nameFuncChord: VERBATIM PORT from legacy MusicData.hs (lines 906-940)
-- This function implements CHORD naming for extended harmonies (4+ pitches).
-- Does NOT reduce to triads - names the full pitch content.
-------------------------------------------------------------------------------

-- |Chord naming function ported VERBATIM from legacy MusicData.hs
-- Different from triad naming - handles extended harmonies (7ths, 9ths, etc.)
nameFuncChord :: ([PitchClass] -> [PitchClass]) -> [PitchClass] -> String -> String
nameFuncChord :: ([PitchClass] -> [PitchClass]) -> [PitchClass] -> ShowS
nameFuncChord [PitchClass] -> [PitchClass]
f [PitchClass]
xs =
  let
    zs :: [Int]
zs = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int) -> (PitchClass -> Int) -> PitchClass -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PitchClass -> Int
unPitchClass (PitchClass -> Int) -> [PitchClass] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [PitchClass] -> [PitchClass]
f [PitchClass]
xs :: [Int]
    chain :: [ShowS]
chain =
      [(String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
0,Int
4,Int
7] Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
1,Int
2,Int
3,Int
5,Int
6,Int
8,Int
9,Int
10,Int
11] 
        then (String
"maj"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
3 [Int]
zs Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
4,Int
10] then (String
"m"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
3,Int
10] Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
4 [Int]
zs then (String
"m7"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
9 [Int]
zs then (String
"6"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
10 [Int]
zs Bool -> Bool -> Bool
&& (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
3 [Int]
zs Bool -> Bool -> Bool
|| (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
3,Int
4]) then (String
"7"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
11 [Int]
zs then (String
"maj7"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
2,Int
5] Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
3,Int
4] then (String
"sus2/4"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
5 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
2 [Int]
zs Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
3,Int
4]
        then (String
"sus2"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
2 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
5 [Int]
zs Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
3,Int
4]
        then (String
"sus4"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if ((Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
6 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
7 [Int]
zs) Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
5 [Int]
zs) 
        Bool -> Bool -> Bool
|| (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
5 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
6 [Int]
zs) then (String
"b5"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if ((Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
8 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
7 [Int]
zs) Bool -> Bool -> Bool
|| (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
8,Int
9]) then (String
"#5"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
2,Int
3,Int
5] Bool -> Bool -> Bool
|| (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
2,Int
4,Int
5]
        then (String
"add9/11"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
5 [Int]
zs Bool -> Bool -> Bool
&& ((Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
2,Int
3] Bool -> Bool -> Bool
|| (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
2,Int
4])
        then (String
"add9"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
2 [Int]
zs Bool -> Bool -> Bool
&& ((Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
5,Int
3] Bool -> Bool -> Bool
|| (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
5,Int
4])
        then (String
"add11"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
6 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
5 [Int]
zs) Bool -> Bool -> Bool
&& (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
7 [Int]
zs Bool -> Bool -> Bool
&& Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem Int
8 [Int]
zs) then (String
"#11"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Int
1 [Int]
zs then (String
"b9"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
3,Int
4] then (String
"#9"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
zs) [Int
7,Int
8] then (String
"b13"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
2,Int
3,Int
4,Int
5] then (String
"no3"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)
      ,if (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Int]
zs) [Int
6,Int
7,Int
8] then (String
"no5"String -> ShowS
forall a. [a] -> [a] -> [a]
++) else (String
""String -> ShowS
forall a. [a] -> [a] -> [a]
++)]
   in (ShowS -> ShowS -> ShowS) -> ShowS -> [ShowS] -> ShowS
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.) ShowS
forall {a}. a -> a
id [ShowS]
chain

-------------------------------------------------------------------------------
-- Triad Construction Functions (exactly 3 pitch classes)
-- If input has >3 pitch classes, reduces via mostConsonant
-------------------------------------------------------------------------------

-- |Build a Triad from an enharmonic function and integer list
-- TRIADS: exactly 3 pitch classes. If >3 input, reduces to best triad.
-- Uses elaborate inversion detection from legacy MusicData.hs
toTriad :: (PitchClass -> NoteName) -> [Int] -> Chord
toTriad :: (PitchClass -> NoteName) -> [Int] -> Chord
toTriad PitchClass -> NoteName
enharm ps :: [Int]
ps@(Int
fund:[Int]
_)
  | [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Int] -> [Int]
forall {a}. Integral a => [a] -> [a]
pcSetInts [Int]
ps) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
3 = (PitchClass -> NoteName) -> [Int] -> Chord
toTriad PitchClass -> NoteName
enharm ([Int] -> Chord) -> [Int] -> Chord
forall a b. (a -> b) -> a -> b
$ [[Int]] -> [Int]
mostConsonant ([[Int]] -> [Int]) -> [[Int]] -> [Int]
forall a b. (a -> b) -> a -> b
$ (PitchClass -> NoteName) -> Int -> [Int] -> [[Int]]
possibleTriadsSimple PitchClass -> NoteName
enharm Int
fund ([Int] -> [Int]
forall a. HasCallStack => [a] -> [a]
tail [Int]
ps)
  | Bool
otherwise = 
    let normalizedPs :: [Int]
normalizedPs = Int -> [Int] -> [Int]
normalizeWithFund Int
fund [Int]
ps
        pcs :: [PitchClass]
pcs = (Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map Int -> PitchClass
mkPitchClass [Int]
normalizedPs
        bass :: PitchClass
bass = Int -> PitchClass
mkPitchClass ([Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int]
normalizedPs)
        invs :: [[PitchClass]]
invs = [PitchClass] -> [[PitchClass]]
inversions [PitchClass]
pcs
        headInv :: [PitchClass]
headInv = [[PitchClass]] -> [PitchClass]
forall a. HasCallStack => [a] -> a
head [[PitchClass]]
invs
        -- Get root offset from inversion pattern
        rootOffset :: Int
rootOffset = case [PitchClass]
headInv of
          [P Int
0, P Int
4, P Int
7] -> Int
0   -- Root position major
          [P Int
0, P Int
3, P Int
7] -> Int
0   -- Root position minor
          [P Int
0, P Int
3, P Int
8] -> Int
8   -- 1st inv major
          [P Int
0, P Int
4, P Int
9] -> Int
9   -- 1st inv minor
          [P Int
0, P Int
5, P Int
9] -> Int
5   -- 2nd inv major
          [P Int
0, P Int
5, P Int
8] -> Int
5   -- 2nd inv minor
          [P Int
0, P Int
3, P Int
6] -> Int
0   -- Root position dim
          [P Int
0, P Int
6, P Int
9] -> Int
6   -- 2nd inv dim
          [P Int
0, P Int
3, P Int
9] -> Int
9   -- 1st inv dim
          [PitchClass]
_ -> Int
0                 -- Fallback (includes all root position chords)
        rootPC :: PitchClass
rootPC = PitchClass
bass PitchClass -> PitchClass -> PitchClass
forall a. Num a => a -> a -> a
+ Int -> PitchClass
P Int
rootOffset
        -- Compute root-relative intervals for naming
        rootRelativePCs :: [PitchClass]
rootRelativePCs = [PitchClass] -> [PitchClass]
forall a. Ord a => [a] -> [a]
sort ([PitchClass] -> [PitchClass]) -> [PitchClass] -> [PitchClass]
forall a b. (a -> b) -> a -> b
$ (PitchClass -> PitchClass) -> [PitchClass] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map (\PitchClass
p -> PitchClass
p PitchClass -> PitchClass -> PitchClass
forall a. Num a => a -> a -> a
- PitchClass
rootPC) [PitchClass]
pcs
        functionality :: String
functionality = ([PitchClass] -> [PitchClass]) -> [PitchClass] -> ShowS
nameFuncTriad [PitchClass] -> [PitchClass]
zeroFormPC [PitchClass]
rootRelativePCs String
""
        -- Get root name and inversion suffix
        invResult :: (NoteName, String)
invResult = (PitchClass -> NoteName) -> [Int] -> (NoteName, String)
detectInversion PitchClass -> NoteName
enharm [Int]
normalizedPs
    in NoteName -> String -> [Integer] -> Chord
Chord ((NoteName, String) -> NoteName
forall a b. (a, b) -> a
fst (NoteName, String)
invResult) (String
functionality String -> ShowS
forall a. [a] -> [a] -> [a]
++ (NoteName, String) -> String
forall a b. (a, b) -> b
snd (NoteName, String)
invResult) ((Int -> Integer) -> [Int] -> [Integer]
forall a b. (a -> b) -> [a] -> [b]
map Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral [Int]
ps)
  where
    pcSetInts :: [a] -> [a]
pcSetInts [a]
xs = [a] -> [a]
forall a. Eq a => [a] -> [a]
List.nub ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ [a] -> [a]
forall a. Ord a => [a] -> [a]
sort ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ (a -> a) -> [a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (a -> a -> a
forall a. Integral a => a -> a -> a
`mod` a
12) [a]
xs
toTriad PitchClass -> NoteName
_ [] = NoteName -> String -> [Integer] -> Chord
Chord NoteName
C String
"N/A" []

-- |Shortcut with flat spelling for triads
flatTriad :: [Int] -> Chord
flatTriad :: [Int] -> Chord
flatTriad = (PitchClass -> NoteName) -> [Int] -> Chord
toTriad PitchClass -> NoteName
flat

-- |Shortcut with sharp spelling for triads
sharpTriad :: [Int] -> Chord
sharpTriad :: [Int] -> Chord
sharpTriad = (PitchClass -> NoteName) -> [Int] -> Chord
toTriad PitchClass -> NoteName
sharp

-------------------------------------------------------------------------------
-- Chord Construction Functions (preserves all pitch classes)
-- Does NOT reduce to triads - names the full pitch content
-------------------------------------------------------------------------------

-- |Build a Chord from an enharmonic function and integer list
-- CHORDS: preserves all pitches, uses chord-specific naming for extended harmonies
-- Ported from legacy MusicData.hs toChord (lines 896-941)
toChord :: (PitchClass -> NoteName) -> [Int] -> Chord
toChord :: (PitchClass -> NoteName) -> [Int] -> Chord
toChord PitchClass -> NoteName
enharm ps :: [Int]
ps@(Int
fund:[Int]
tones) = 
  let chord :: [Int]
chord = (Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
fund) (Int -> Int) -> [Int] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([Int] -> [Int]
forall {a}. Integral a => [a] -> [a]
sortedZeroForm ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ Int
fund Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: ([Int] -> [Int]
forall a. [a] -> [a]
reverse ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort [Int]
tones))
      functionality :: String
functionality = ([PitchClass] -> [PitchClass]) -> [PitchClass] -> ShowS
nameFuncChord [PitchClass] -> [PitchClass]
zeroFormPC ((Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map Int -> PitchClass
mkPitchClass [Int]
chord) String
""
  in NoteName -> String -> [Integer] -> Chord
Chord (PitchClass -> NoteName
enharm (PitchClass -> NoteName) -> PitchClass -> NoteName
forall a b. (a -> b) -> a -> b
$ Int -> PitchClass
mkPitchClass ([Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int]
chord)) String
functionality ((Int -> Integer) -> [Int] -> [Integer]
forall a b. (a -> b) -> [a] -> [b]
map Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([Int] -> [Integer]) -> [Int] -> [Integer]
forall a b. (a -> b) -> a -> b
$ (Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) [Int]
chord)
  where
    sortedZeroForm :: [a] -> [a]
sortedZeroForm [a]
xs = 
      let m :: a
m = [a] -> a
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [a]
xs 
      in [a] -> [a]
forall a. Ord a => [a] -> [a]
sort ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ (a -> a) -> [a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (\a
n -> (a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
m) a -> a -> a
forall a. Integral a => a -> a -> a
`mod` a
12) [a]
xs
toChord PitchClass -> NoteName
enharm [] = NoteName -> String -> [Integer] -> Chord
Chord (PitchClass -> NoteName
enharm (Int -> PitchClass
P Int
0)) String
"N/A" []

-- |Shortcut with flat spelling for chords
flatChord :: [Int] -> Chord
flatChord :: [Int] -> Chord
flatChord = (PitchClass -> NoteName) -> [Int] -> Chord
toChord PitchClass -> NoteName
flat

-- |Shortcut with sharp spelling for chords
sharpChord :: [Int] -> Chord
sharpChord :: [Int] -> Chord
sharpChord = (PitchClass -> NoteName) -> [Int] -> Chord
toChord PitchClass -> NoteName
sharp

-- |Convert a pair of Chords to a Cadence
toCadence :: (Chord, Chord) -> Cadence
toCadence :: (Chord, Chord) -> Cadence
toCadence (Chord
fromChord, Chord
toChord') =
  let fromRoot :: PitchClass
fromRoot = NoteName -> PitchClass
pitchClass (Chord -> NoteName
chordNoteName Chord
fromChord)
      toRoot :: PitchClass
toRoot = NoteName -> PitchClass
pitchClass (Chord -> NoteName
chordNoteName Chord
toChord')
      mvmt :: Movement
mvmt = PitchClass -> PitchClass -> Movement
toMovement PitchClass
fromRoot PitchClass
toRoot
      toIntervals :: [PitchClass]
toIntervals = (Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map Int -> PitchClass
mkPitchClass ([Int] -> [PitchClass]) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> a -> b
$ Int -> [Int] -> [Int]
forall a. Int -> [a] -> [a]
take Int
3 ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ (Integer -> Int) -> [Integer] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Chord -> [Integer]
chordIntervals Chord
toChord')
  in String -> Movement -> [PitchClass] -> Cadence
Cadence (Chord -> String
chordFunctionality Chord
toChord') Movement
mvmt ([PitchClass] -> [PitchClass]
zeroFormPC [PitchClass]
toIntervals)

-------------------------------------------------------------------------------
-- State Conversion
-------------------------------------------------------------------------------

-- |Convert ChordState to the underlying Chord
fromChordState :: ChordState -> Chord
fromChordState :: ChordState -> Chord
fromChordState = ChordState -> Chord
stateChord

-- |Convert CadenceState back to a Chord (applying the root and spelling)
fromCadenceState :: CadenceState -> Chord
fromCadenceState :: CadenceState -> Chord
fromCadenceState (CadenceState Cadence
cadence NoteName
root EnharmonicSpelling
spelling) =
  let rootPC :: PitchClass
rootPC = NoteName -> PitchClass
pitchClass NoteName
root
      enharm :: PitchClass -> NoteName
enharm = EnharmonicSpelling -> PitchClass -> NoteName
enharmonicFunc EnharmonicSpelling
spelling
      tones :: [PitchClass]
tones = Cadence -> [PitchClass]
cadenceIntervals Cadence
cadence
      pitches :: [Int]
pitches = (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (\PitchClass
t -> PitchClass -> Int
unPitchClass (PitchClass
t PitchClass -> PitchClass -> PitchClass
forall a. Num a => a -> a -> a
+ PitchClass
rootPC)) [PitchClass]
tones
  in (PitchClass -> NoteName) -> [Int] -> Chord
toTriad PitchClass -> NoteName
enharm [Int]
pitches

-- |Initialize a CadenceState from movement, note name, and quality intervals.
-- Enharmonic spelling is inferred from the chord's absolute pitch content.
initCadenceState :: Int -> String -> [Int] -> CadenceState
initCadenceState :: Int -> String -> [Int] -> CadenceState
initCadenceState Int
movement String
note [Int]
quality =
  let approach :: Movement
approach = PitchClass -> PitchClass -> Movement
toMovement (Int -> PitchClass
P Int
0) (Int -> PitchClass
mkPitchClass Int
movement)
      from :: Chord
from = [Int] -> Chord
flatTriad [Int
0]
      toIntervals :: [Int]
toIntervals = (Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ PitchClass -> Int
unPitchClass (Movement -> PitchClass
fromMovement Movement
approach)) ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ [Int] -> [Int]
forall {a}. Integral a => [a] -> [a]
zeroFormInts [Int]
quality
      to :: Chord
to = [Int] -> Chord
flatTriad [Int]
toIntervals
      root :: NoteName
root = String -> NoteName
readNoteName String
note
      cad :: Cadence
cad = (Chord, Chord) -> Cadence
toCadence (Chord
from, Chord
to)
      -- Infer spelling from absolute pitches
      rootPC :: PitchClass
rootPC = NoteName -> PitchClass
pitchClass NoteName
root
      tones :: [PitchClass]
tones = Cadence -> [PitchClass]
cadenceIntervals Cadence
cad
      absolutePitches :: [Int]
absolutePitches = (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (\PitchClass
t -> PitchClass -> Int
unPitchClass (PitchClass
t PitchClass -> PitchClass -> PitchClass
forall a. Num a => a -> a -> a
+ PitchClass
rootPC)) [PitchClass]
tones
      inferredSpelling :: EnharmonicSpelling
inferredSpelling = [Int] -> EnharmonicSpelling
inferSpelling [Int]
absolutePitches
      spelling :: EnharmonicSpelling
spelling = case NoteName -> Maybe EnharmonicSpelling
noteNameImpliesSpelling NoteName
root of
        Just EnharmonicSpelling
explicit -> EnharmonicSpelling
explicit
        Maybe EnharmonicSpelling
Nothing       -> EnharmonicSpelling
inferredSpelling
  in Cadence -> NoteName -> EnharmonicSpelling -> CadenceState
CadenceState Cadence
cad NoteName
root EnharmonicSpelling
spelling
  where
    zeroFormInts :: [a] -> [a]
zeroFormInts [a]
xs = let m :: a
m = [a] -> a
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [a]
xs in [a] -> [a]
forall a. Ord a => [a] -> [a]
sort ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ (a -> a) -> [a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (\a
n -> (a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
m) a -> a -> a
forall a. Integral a => a -> a -> a
`mod` a
12) [a]
xs

-- |Build a CadenceState from a root, movement, and root-relative intervals,
-- preserving full cardinality. The non-truncating counterpart to
-- 'initCadenceState', which routes through 'flatTriad' \/ 'toCadence' and
-- silently reduces >3 PCs to a triad. Intervals are root-relative
-- (0 = the root; inserted if missing); stored in zero form (sorted,
-- deduped mod 12). Functionality dispatches on cardinality: <=3 uses the
-- triad namer, 4+ the chord namer. Spelling from the typed root when it
-- implies one (Eb → flat), otherwise inferred from absolute pitch content.
mkCadenceStatePCs :: NoteName -> Movement -> [Int] -> CadenceState
mkCadenceStatePCs :: NoteName -> Movement -> [Int] -> CadenceState
mkCadenceStatePCs NoteName
root Movement
movement [Int]
intervals =
  let rootPC :: Int
rootPC          = PitchClass -> Int
unPitchClass (NoteName -> PitchClass
pitchClass NoteName
root)
      ivs :: [Int]
ivs             = [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ [Int] -> [Int]
forall a. Eq a => [a] -> [a]
List.nub ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ (Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) (Int
0 Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int]
intervals)
      pcs :: [PitchClass]
pcs             = (Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map Int -> PitchClass
mkPitchClass [Int]
ivs
      functionality :: String
functionality
        | [PitchClass] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PitchClass]
pcs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
3 = [PitchClass] -> String
toFunctionality [PitchClass]
pcs
        | Bool
otherwise       = [PitchClass] -> String
toFunctionalityChord [PitchClass]
pcs
      absolutePitches :: [Int]
absolutePitches = (Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (\Int
i -> (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
rootPC) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) [Int]
ivs
      spelling :: EnharmonicSpelling
spelling = case NoteName -> Maybe EnharmonicSpelling
noteNameImpliesSpelling NoteName
root of
        Just EnharmonicSpelling
explicit -> EnharmonicSpelling
explicit
        Maybe EnharmonicSpelling
Nothing       -> [Int] -> EnharmonicSpelling
inferSpelling [Int]
absolutePitches
  in Cadence -> NoteName -> EnharmonicSpelling -> CadenceState
CadenceState (String -> Movement -> [PitchClass] -> Cadence
Cadence String
functionality Movement
movement [PitchClass]
pcs) NoteName
root EnharmonicSpelling
spelling

-------------------------------------------------------------------------------
-- Walk projection (gen4)
-------------------------------------------------------------------------------

-- |Project a Cadence onto its most consonant ROOTED embedded triad.
-- Identity for <=3 intervals (every corpus-generated cadence). For >3:
-- enumerates the 3-subsets that keep the root ([0,a,b] over the nonzero
-- intervals), picks the least dissonant via the Layer-B @mostConsonant@
-- replica, and renames with the triad namer. Root, movement, and (via
-- 'walkTriadState') spelling are preserved, so the projected cadence's
-- 'show' is always a corpus-shaped graph key. This is gen4's walk shadow:
-- the added tone can reinterpret the harmony (e.g. [0,3,6]+7 projects to
-- [0,3,7] minor) and thereby steer the next step.
walkTriadCadence :: Cadence -> Cadence
walkTriadCadence :: Cadence -> Cadence
walkTriadCadence Cadence
cad
  | [PitchClass] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PitchClass]
ivs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
3 = Cadence
cad
  | [[Int]] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Int]]
triads     = Cadence
cad
  | Bool
otherwise       =
      let best :: [Int]
best = [[Int]] -> [Int]
mostConsonant [[Int]]
triads
          zf :: [PitchClass]
zf   = (Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map Int -> PitchClass
mkPitchClass [Int]
best
      in String -> Movement -> [PitchClass] -> Cadence
Cadence ([PitchClass] -> String
corpusFunctionality [PitchClass]
zf) (Cadence -> Movement
cadenceMovement Cadence
cad) [PitchClass]
zf
  where
    ivs :: [PitchClass]
ivs    = Cadence -> [PitchClass]
cadenceIntervals Cadence
cad
    uppers :: [Int]
uppers = [Int] -> [Int]
forall a. Eq a => [a] -> [a]
List.nub [ Int
i | Int
i <- (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (\PitchClass
p -> PitchClass -> Int
unPitchClass PitchClass
p Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) [PitchClass]
ivs, Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0 ]
    triads :: [[Int]]
triads = [ [Int
0, Int
a, Int
b] | Int
a <- [Int]
uppers, Int
b <- [Int]
uppers, Int
a Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
b ]

-- |State-level walk projection: 'walkTriadCadence' on the cadence, root
-- and spelling untouched. Identity for triad states.
walkTriadState :: CadenceState -> CadenceState
walkTriadState :: CadenceState -> CadenceState
walkTriadState (CadenceState Cadence
cad NoteName
root EnharmonicSpelling
spelling) =
  Cadence -> NoteName -> EnharmonicSpelling -> CadenceState
CadenceState (Cadence -> Cadence
walkTriadCadence Cadence
cad) NoteName
root EnharmonicSpelling
spelling

-------------------------------------------------------------------------------
-- Tracing (for maximum verbosity diagnostics)
-------------------------------------------------------------------------------

-- |Trace of toTriad transformation steps
data ToTriadTrace = ToTriadTrace
  { ToTriadTrace -> String
tttRawDbIntervals   :: String    -- ^ Raw zero-form intervals from DB: "[P 0,P 4,P 7]"
  , ToTriadTrace -> String
tttRawDbMovement    :: String    -- ^ Raw movement from DB: "desc 3"
  , ToTriadTrace -> String
tttRawDbFunctionality :: String  -- ^ Raw stored functionality from DB: "maj"
  , ToTriadTrace -> Int
tttRootPC           :: Int       -- ^ Root pitch class (0-11)
  , ToTriadTrace -> String
tttRootNoteName     :: String    -- ^ Root note name before transform
  , ToTriadTrace -> [Int]
tttTones            :: [Int]     -- ^ Raw cadence intervals as Ints before transposition
  , ToTriadTrace -> [Int]
tttTransposedPitches:: [Int]     -- ^ Pitches after adding rootPC to tones (STEP 2)
  , ToTriadTrace -> [Int]
tttNormalizedPs     :: [Int]     -- ^ Result of normalizeWithFund (STEP 3)
  , ToTriadTrace -> [Int]
tttZeroForm         :: [Int]     -- ^ Result of zeroFormPC on normalized pitches (STEP 4)
  , ToTriadTrace -> String
tttDetectedRoot     :: String    -- ^ Root from detectInversion
  , ToTriadTrace -> String
tttFunctionality    :: String    -- ^ Result of nameFuncTriad
  , ToTriadTrace -> String
tttFinalChord       :: String    -- ^ Final rendered chord (root + functionality)
  , ToTriadTrace -> String
tttStoredFunc       :: String    -- ^ Original functionality stored in cadence
  } deriving (Int -> ToTriadTrace -> ShowS
[ToTriadTrace] -> ShowS
ToTriadTrace -> String
(Int -> ToTriadTrace -> ShowS)
-> (ToTriadTrace -> String)
-> ([ToTriadTrace] -> ShowS)
-> Show ToTriadTrace
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ToTriadTrace -> ShowS
showsPrec :: Int -> ToTriadTrace -> ShowS
$cshow :: ToTriadTrace -> String
show :: ToTriadTrace -> String
$cshowList :: [ToTriadTrace] -> ShowS
showList :: [ToTriadTrace] -> ShowS
Show, ToTriadTrace -> ToTriadTrace -> Bool
(ToTriadTrace -> ToTriadTrace -> Bool)
-> (ToTriadTrace -> ToTriadTrace -> Bool) -> Eq ToTriadTrace
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ToTriadTrace -> ToTriadTrace -> Bool
== :: ToTriadTrace -> ToTriadTrace -> Bool
$c/= :: ToTriadTrace -> ToTriadTrace -> Bool
/= :: ToTriadTrace -> ToTriadTrace -> Bool
Eq)

-- |Convert CadenceState to Chord with full transformation trace.
-- Used for maximum verbosity diagnostics (gen''). Includes raw DB data plus all transformation stages.
fromCadenceStateTraced :: CadenceState -> (Chord, ToTriadTrace)
fromCadenceStateTraced :: CadenceState -> (Chord, ToTriadTrace)
fromCadenceStateTraced (CadenceState Cadence
cadence NoteName
root EnharmonicSpelling
spelling) =
  let rootPC :: PitchClass
rootPC = NoteName -> PitchClass
pitchClass NoteName
root
      rootPCInt :: Int
rootPCInt = PitchClass -> Int
unPitchClass PitchClass
rootPC
      enharm :: PitchClass -> NoteName
enharm = EnharmonicSpelling -> PitchClass -> NoteName
enharmonicFunc EnharmonicSpelling
spelling
      tones :: [PitchClass]
tones = Cadence -> [PitchClass]
cadenceIntervals Cadence
cadence
      tonesInts :: [Int]
tonesInts = (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map PitchClass -> Int
unPitchClass [PitchClass]
tones
      pitches :: [Int]
pitches = (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (\PitchClass
t -> PitchClass -> Int
unPitchClass (PitchClass
t PitchClass -> PitchClass -> PitchClass
forall a. Num a => a -> a -> a
+ PitchClass
rootPC)) [PitchClass]
tones
      
      -- Trace toTriad internals (matching toTriad logic for correct functionality)
      fund :: Int
fund = [Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int]
pitches
      normalizedPs :: [Int]
normalizedPs = Int -> [Int] -> [Int]
normalizeWithFund Int
fund [Int]
pitches
      pcs :: [PitchClass]
pcs = (Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map Int -> PitchClass
mkPitchClass [Int]
normalizedPs
      bass :: PitchClass
bass = Int -> PitchClass
mkPitchClass ([Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int]
normalizedPs)
      invs :: [[PitchClass]]
invs = [PitchClass] -> [[PitchClass]]
inversions [PitchClass]
pcs
      headInv :: [PitchClass]
headInv = [[PitchClass]] -> [PitchClass]
forall a. HasCallStack => [a] -> a
head [[PitchClass]]
invs
      -- Get root offset from inversion pattern (same as toTriad lines 452-465)
      rootOffset :: Int
rootOffset = case [PitchClass]
headInv of
        [P Int
0, P Int
4, P Int
7] -> Int
0   -- Root position major
        [P Int
0, P Int
3, P Int
7] -> Int
0   -- Root position minor
        [P Int
0, P Int
3, P Int
8] -> Int
8   -- 1st inv major
        [P Int
0, P Int
4, P Int
9] -> Int
9   -- 1st inv minor
        [P Int
0, P Int
5, P Int
9] -> Int
5   -- 2nd inv major
        [P Int
0, P Int
5, P Int
8] -> Int
5   -- 2nd inv minor
        [P Int
0, P Int
3, P Int
6] -> Int
0   -- Root position dim
        [P Int
0, P Int
6, P Int
9] -> Int
6   -- 2nd inv dim
        [P Int
0, P Int
3, P Int
9] -> Int
9   -- 1st inv dim
        [PitchClass]
_ -> Int
0                 -- Fallback (includes all root position chords)
      rootPC_computed :: PitchClass
rootPC_computed = PitchClass
bass PitchClass -> PitchClass -> PitchClass
forall a. Num a => a -> a -> a
+ Int -> PitchClass
P Int
rootOffset
      -- Compute root-relative intervals for naming (same as toTriad line 468)
      rootRelativePCs :: [PitchClass]
rootRelativePCs = [PitchClass] -> [PitchClass]
forall a. Ord a => [a] -> [a]
sort ([PitchClass] -> [PitchClass]) -> [PitchClass] -> [PitchClass]
forall a b. (a -> b) -> a -> b
$ (PitchClass -> PitchClass) -> [PitchClass] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map (\PitchClass
p -> PitchClass
p PitchClass -> PitchClass -> PitchClass
forall a. Num a => a -> a -> a
- PitchClass
rootPC_computed) [PitchClass]
pcs
      zeroForm :: [Int]
zeroForm = (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map PitchClass -> Int
unPitchClass ([PitchClass] -> [Int]) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> a -> b
$ [PitchClass] -> [PitchClass]
zeroFormPC [PitchClass]
pcs
      invResult :: (NoteName, String)
invResult = (PitchClass -> NoteName) -> [Int] -> (NoteName, String)
detectInversion PitchClass -> NoteName
enharm [Int]
normalizedPs
      functionality :: String
functionality = ([PitchClass] -> [PitchClass]) -> [PitchClass] -> ShowS
nameFuncTriad [PitchClass] -> [PitchClass]
zeroFormPC [PitchClass]
rootRelativePCs String
""
      finalChord :: Chord
finalChord = NoteName -> String -> [Integer] -> Chord
Chord ((NoteName, String) -> NoteName
forall a b. (a, b) -> a
fst (NoteName, String)
invResult) (String
functionality String -> ShowS
forall a. [a] -> [a] -> [a]
++ (NoteName, String) -> String
forall a b. (a, b) -> b
snd (NoteName, String)
invResult) ((Int -> Integer) -> [Int] -> [Integer]
forall a b. (a -> b) -> [a] -> [b]
map Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral [Int]
pitches)
      
      -- Raw DB data
      dbIntervals :: String
dbIntervals = [PitchClass] -> String
forall a. Show a => a -> String
show [PitchClass]
tones
      dbMovement :: String
dbMovement = Movement -> String
forall a. Show a => a -> String
show (Cadence -> Movement
cadenceMovement Cadence
cadence)
      dbFunctionality :: String
dbFunctionality = Cadence -> String
cadenceFunctionality Cadence
cadence
      
      trace :: ToTriadTrace
trace = ToTriadTrace
        { tttRawDbIntervals :: String
tttRawDbIntervals = String
dbIntervals
        , tttRawDbMovement :: String
tttRawDbMovement = String
dbMovement
        , tttRawDbFunctionality :: String
tttRawDbFunctionality = String
dbFunctionality
        , tttRootPC :: Int
tttRootPC = Int
rootPCInt
        , tttRootNoteName :: String
tttRootNoteName = NoteName -> String
forall a. Show a => a -> String
show NoteName
root
        , tttTones :: [Int]
tttTones = [Int]
tonesInts
        , tttTransposedPitches :: [Int]
tttTransposedPitches = [Int]
pitches
        , tttNormalizedPs :: [Int]
tttNormalizedPs = [Int]
normalizedPs
        , tttZeroForm :: [Int]
tttZeroForm = [Int]
zeroForm
        , tttDetectedRoot :: String
tttDetectedRoot = NoteName -> String
forall a. Show a => a -> String
show ((NoteName, String) -> NoteName
forall a b. (a, b) -> a
fst (NoteName, String)
invResult)
        , tttFunctionality :: String
tttFunctionality = String
functionality
        , tttFinalChord :: String
tttFinalChord = NoteName -> String
forall a. Show a => a -> String
show ((NoteName, String) -> NoteName
forall a b. (a, b) -> a
fst (NoteName, String)
invResult) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
functionality String -> ShowS
forall a. [a] -> [a] -> [a]
++ (NoteName, String) -> String
forall a b. (a, b) -> b
snd (NoteName, String)
invResult
        , tttStoredFunc :: String
tttStoredFunc = String
dbFunctionality
        }
  in (Chord
finalChord, ToTriadTrace
trace)

-------------------------------------------------------------------------------
-- DB Serialization (compatible with Neo4j format)
-------------------------------------------------------------------------------

-- |Construct a Cadence from DB text format (movement string, chord string)
-- 
-- Example:
--   constructCadence ("desc 3", "[P 0,P 3,P 8]")
--   => Cadence { cadenceFunctionality = "maj_1stInv", cadenceMovement = Desc (P 3), ... }
constructCadence :: (String, String) -> Cadence
constructCadence :: (String, String) -> Cadence
constructCadence (String
movementStr, String
chordStr) =
  let pitches :: [PitchClass]
pitches = String -> [PitchClass]
forall a. Read a => String -> a
read String
chordStr :: [PitchClass]
      functionality :: String
functionality = [PitchClass] -> String
corpusFunctionality [PitchClass]
pitches
      movement :: Movement
movement = String -> Movement
forall a. Read a => String -> a
read String
movementStr :: Movement
  in String -> Movement -> [PitchClass] -> Cadence
Cadence String
functionality Movement
movement [PitchClass]
pitches

-- |Name a zero-form triad exactly as the corpus stores it. The graph's
-- node keys (@show@ = movement + functionality) carry the names below;
-- any cadence whose @show@ is used as a fetch key MUST be named through
-- here, or the walk silently drops to fallback-only after landing on
-- that form (a latent bug fixed 2026-08-19: 'constructCadence'
-- previously named via bare 'toFunctionality', so every graph-selected
-- inversion candidate — @[0,3,8]@ read back as @min#5@ instead of the
-- stored @maj_1stInv@ — produced a keyless next fetch).
--
-- The table is the complete 55-form vocabulary transcribed verbatim from
-- a live corpus dump (2026-08-19,
-- @MATCH (c:Cadence) RETURN DISTINCT c.chord, c.show@). It reflects the
-- LEGACY naming rules the database was ingested under — including the
-- forms where the modernised @nameFuncTriad@ deliberately diverges
-- (@[0,2,7]@ is stored @sus4_1stInv@, modern says @sus2@; @[0,5,10]@ is
-- stored @sus4_2ndInv@, modern says @7sus4@) — so it cannot be derived
-- from the current namers. If the corpus is ever re-ingested, regenerate
-- this table from the same query.
--
-- Non-triad input (fewer\/more than 3 PCs) falls back to the current
-- namers — such sets are never corpus keys.
corpusFunctionality :: [PitchClass] -> Functionality
corpusFunctionality :: [PitchClass] -> String
corpusFunctionality [PitchClass]
pcs =
  case [PitchClass] -> [([PitchClass], String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup ([PitchClass] -> [PitchClass]
zeroFormPC [PitchClass]
pcs) [([PitchClass], String)]
corpusNameTable of
    Just String
name -> String
name
    Maybe String
Nothing
      | [PitchClass] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PitchClass]
pcs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
3 -> [PitchClass] -> String
toFunctionality [PitchClass]
pcs
      | Bool
otherwise       -> [PitchClass] -> String
toFunctionalityChord [PitchClass]
pcs

-- |Complete corpus triad-name vocabulary: zero form → stored functionality.
corpusNameTable :: [([PitchClass], Functionality)]
corpusNameTable :: [([PitchClass], String)]
corpusNameTable = (([Int], String) -> ([PitchClass], String))
-> [([Int], String)] -> [([PitchClass], String)]
forall a b. (a -> b) -> [a] -> [b]
map (\([Int]
is, String
n) -> ((Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map Int -> PitchClass
P [Int]
is, String
n))
  [ ([Int
0,Int
1,Int
2],   String
"sus2b9no5"),    ([Int
0,Int
1,Int
3],   String
"minb9no5")
  , ([Int
0,Int
1,Int
4],   String
"majb9no5"),     ([Int
0,Int
1,Int
5],   String
"sus4b9no5")
  , ([Int
0,Int
1,Int
6],   String
"b9b5no3"),      ([Int
0,Int
1,Int
7],   String
"b9no3")
  , ([Int
0,Int
1,Int
8],   String
"b9#5no3"),      ([Int
0,Int
1,Int
9],   String
"6b9no3no5")
  , ([Int
0,Int
1,Int
10],  String
"7b9no3no5"),    ([Int
0,Int
1,Int
11],  String
"maj7b9no3no5")
  , ([Int
0,Int
2,Int
3],   String
"minadd9no5"),   ([Int
0,Int
2,Int
4],   String
"majadd9no5")
  , ([Int
0,Int
2,Int
5],   String
"sus2/4no5"),    ([Int
0,Int
2,Int
6],   String
"sus2b5")
  , ([Int
0,Int
2,Int
7],   String
"sus4_1stInv"),  ([Int
0,Int
2,Int
8],   String
"sus2#5")
  , ([Int
0,Int
2,Int
9],   String
"6sus2no5"),     ([Int
0,Int
2,Int
10],  String
"7sus2no5")
  , ([Int
0,Int
2,Int
11],  String
"maj7sus2no5"),  ([Int
0,Int
3,Int
4],   String
"#9no5")
  , ([Int
0,Int
3,Int
5],   String
"minadd11no5"),  ([Int
0,Int
3,Int
6],   String
"dim")
  , ([Int
0,Int
3,Int
7],   String
"min"),          ([Int
0,Int
3,Int
8],   String
"maj_1stInv")
  , ([Int
0,Int
3,Int
9],   String
"dim_1stInv"),   ([Int
0,Int
3,Int
10],  String
"min7no5")
  , ([Int
0,Int
3,Int
11],  String
"minmaj7no5"),   ([Int
0,Int
4,Int
5],   String
"majadd11no5")
  , ([Int
0,Int
4,Int
6],   String
"majb5"),        ([Int
0,Int
4,Int
7],   String
"maj")
  , ([Int
0,Int
4,Int
8],   String
"aug"),          ([Int
0,Int
4,Int
9],   String
"min_1stInv")
  , ([Int
0,Int
4,Int
10],  String
"7no5"),         ([Int
0,Int
4,Int
11],  String
"maj7no5")
  , ([Int
0,Int
5,Int
6],   String
"sus4b5"),       ([Int
0,Int
5,Int
7],   String
"sus4")
  , ([Int
0,Int
5,Int
8],   String
"min_2ndInv"),   ([Int
0,Int
5,Int
9],   String
"maj_2ndInv")
  , ([Int
0,Int
5,Int
10],  String
"sus4_2ndInv"),  ([Int
0,Int
5,Int
11],  String
"maj7sus4no5")
  , ([Int
0,Int
6,Int
7],   String
"#11no3"),       ([Int
0,Int
6,Int
8],   String
"#11#5no3")
  , ([Int
0,Int
6,Int
9],   String
"dim_2ndInv"),   ([Int
0,Int
6,Int
10],  String
"7b5no3")
  , ([Int
0,Int
6,Int
11],  String
"maj7b5no3"),    ([Int
0,Int
7,Int
8],   String
"b13no3")
  , ([Int
0,Int
7,Int
9],   String
"6no3"),         ([Int
0,Int
7,Int
10],  String
"7no3")
  , ([Int
0,Int
7,Int
11],  String
"maj7no3"),      ([Int
0,Int
8,Int
9],   String
"6#5no3")
  , ([Int
0,Int
8,Int
10],  String
"7#5no3"),       ([Int
0,Int
8,Int
11],  String
"maj7#5no3")
  , ([Int
0,Int
9,Int
10],  String
"67no3no5"),     ([Int
0,Int
9,Int
11],  String
"6maj7no3no5")
  , ([Int
0,Int
10,Int
11], String
"7maj7no3no5")
  ]

-- |Deconstruct a Cadence to DB text format (movement, pitch class list)
-- Returns the Movement and [PitchClass] for serialization
deconstructCadence :: Cadence -> (Movement, [PitchClass])
deconstructCadence :: Cadence -> (Movement, [PitchClass])
deconstructCadence (Cadence String
_ Movement
mvmt [PitchClass]
intervals) = (Movement
mvmt, [PitchClass]
intervals)

-------------------------------------------------------------------------------
-- Utilities
-------------------------------------------------------------------------------

-- |Extract the root note from a Chord
rootNote :: Chord -> NoteName
rootNote :: Chord -> NoteName
rootNote = Chord -> NoteName
chordNoteName

-- |Generate all cyclic inversions of a pitch set (in zero form)
-- Each inversion is transformed to zero form for proper comparison
inversions :: [PitchClass] -> [[PitchClass]]
inversions :: [PitchClass] -> [[PitchClass]]
inversions [PitchClass]
ps = ([Int] -> [PitchClass]) -> [[Int]] -> [[PitchClass]]
forall a b. (a -> b) -> [a] -> [b]
map ([PitchClass] -> [PitchClass]
zeroFormPC ([PitchClass] -> [PitchClass])
-> ([Int] -> [PitchClass]) -> [Int] -> [PitchClass]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> PitchClass
P (Int -> PitchClass) -> (Int -> Int) -> Int -> PitchClass
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral)) ([[Int]] -> [[PitchClass]]) -> [[Int]] -> [[PitchClass]]
forall a b. (a -> b) -> a -> b
$ [Int] -> [[Int]]
forall {a}. [a] -> [[a]]
simpleRotations ((PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map PitchClass -> Int
unPitchClass [PitchClass]
ps)
  where
    simpleRotations :: [a] -> [[a]]
simpleRotations [a]
xs = Int -> [[a]] -> [[a]]
forall a. Int -> [a] -> [a]
take ([a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs) ([[a]] -> [[a]]) -> [[a]] -> [[a]]
forall a b. (a -> b) -> a -> b
$ ([a] -> [a]) -> [a] -> [[a]]
forall a. (a -> a) -> a -> [a]
iterate [a] -> [a]
forall a. [a] -> [a]
rotate [a]
xs
    rotate :: [a] -> [a]
rotate [a]
ys = [a] -> [a]
forall a. HasCallStack => [a] -> [a]
tail [a]
ys [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [[a] -> a
forall a. HasCallStack => [a] -> a
head [a]
ys]

-- |Normalize a pitch set to its most compact form
-- Ported from legacy MusicData.hs normalForm
normalForm :: [PitchClass] -> [PitchClass]
normalForm :: [PitchClass] -> [PitchClass]
normalForm [PitchClass]
xs
  | [PitchClass] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PitchClass]
pitches Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = [Int -> PitchClass
P Int
0]
  | [PitchClass] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PitchClass]
pitches Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 = [[PitchClass]] -> [PitchClass]
forall a. HasCallStack => [a] -> a
head ([[PitchClass]] -> [PitchClass]) -> [[PitchClass]] -> [PitchClass]
forall a b. (a -> b) -> a -> b
$ [[PitchClass]] -> [[PitchClass]]
filterByLast ([[PitchClass]] -> [[PitchClass]])
-> [[PitchClass]] -> [[PitchClass]]
forall a b. (a -> b) -> a -> b
$ [[PitchClass]]
invs
  | [PitchClass] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PitchClass]
pitches Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
3 = [[PitchClass]] -> [PitchClass]
forall a. HasCallStack => [a] -> a
head ([[PitchClass]] -> [PitchClass]) -> [[PitchClass]] -> [PitchClass]
forall a b. (a -> b) -> a -> b
$ [[PitchClass]] -> [[PitchClass]]
filterBySecondLast ([[PitchClass]] -> [[PitchClass]])
-> [[PitchClass]] -> [[PitchClass]]
forall a b. (a -> b) -> a -> b
$ [[PitchClass]] -> [[PitchClass]]
filterByLast [[PitchClass]]
invs
  | Bool
otherwise           = [[PitchClass]] -> [PitchClass]
forall a. HasCallStack => [a] -> a
head ([[PitchClass]] -> [PitchClass]) -> [[PitchClass]] -> [PitchClass]
forall a b. (a -> b) -> a -> b
$ [[PitchClass]] -> [[PitchClass]]
filterBySecondLast ([[PitchClass]] -> [[PitchClass]])
-> [[PitchClass]] -> [[PitchClass]]
forall a b. (a -> b) -> a -> b
$ [[PitchClass]] -> [[PitchClass]]
filterByLast [[PitchClass]]
invs
  where
    pitches :: [PitchClass]
pitches = [PitchClass] -> [PitchClass]
forall a. Eq a => [a] -> [a]
List.nub [PitchClass]
xs
    invs :: [[PitchClass]]
invs = [PitchClass] -> [[PitchClass]]
inversions [PitchClass]
pitches
    -- Convert to integers for comparison
    toInts :: [PitchClass] -> [Int]
toInts [PitchClass]
ys = (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map PitchClass -> Int
unPitchClass [PitchClass]
ys
    filterByLast :: [[PitchClass]] -> [[PitchClass]]
filterByLast [[PitchClass]]
xss = ([PitchClass] -> Bool) -> [[PitchClass]] -> [[PitchClass]]
forall a. (a -> Bool) -> [a] -> [a]
filter (\[PitchClass]
x -> [Int] -> Int
forall a. HasCallStack => [a] -> a
last ([PitchClass] -> [Int]
toInts [PitchClass]
x) Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [Int] -> Int
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum (([PitchClass] -> Int) -> [[PitchClass]] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map ([Int] -> Int
forall a. HasCallStack => [a] -> a
last ([Int] -> Int) -> ([PitchClass] -> [Int]) -> [PitchClass] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [PitchClass] -> [Int]
toInts) [[PitchClass]]
xss)) [[PitchClass]]
xss
    filterBySecondLast :: [[PitchClass]] -> [[PitchClass]]
filterBySecondLast [[PitchClass]]
xss = 
      let penultimate :: [PitchClass] -> Int
penultimate [PitchClass]
ys = if [PitchClass] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PitchClass]
ys Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 then [PitchClass] -> [Int]
toInts [PitchClass]
ys [Int] -> Int -> Int
forall a. HasCallStack => [a] -> Int -> a
!! ([PitchClass] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PitchClass]
ys Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2) else Int
0
      in ([PitchClass] -> Bool) -> [[PitchClass]] -> [[PitchClass]]
forall a. (a -> Bool) -> [a] -> [a]
filter (\[PitchClass]
x -> [PitchClass] -> Int
penultimate [PitchClass]
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [Int] -> Int
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum (([PitchClass] -> Int) -> [[PitchClass]] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map [PitchClass] -> Int
penultimate [[PitchClass]]
xss)) [[PitchClass]]
xss

-- |Compute prime form (transposition and inversion invariant)
-- Ported from legacy MusicData.hs primeForm
primeForm :: [PitchClass] -> [PitchClass]
primeForm :: [PitchClass] -> [PitchClass]
primeForm [PitchClass]
xs = (Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map Int -> PitchClass
P ([Int] -> [PitchClass]) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> a -> b
$ [Int]
primeInts
  where
    -- Get normal form as integers
    cmpt :: [Int]
cmpt = (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map PitchClass -> Int
unPitchClass ([PitchClass] -> [Int]) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> a -> b
$ [PitchClass] -> [PitchClass]
normalForm [PitchClass]
xs
    -- Invert: 12 - each element, then get normal form of that
    inverted :: [Int]
inverted = (Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (\Int
n -> (Int
12 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) [Int]
cmpt
    invCmpt :: [Int]
invCmpt = (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map PitchClass -> Int
unPitchClass ([PitchClass] -> [Int]) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> a -> b
$ [PitchClass] -> [PitchClass]
normalForm ((Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map Int -> PitchClass
P [Int]
inverted)
    -- Pick the one with smaller sum
    primeInts :: [Int]
primeInts = [[Int]] -> [Int]
forall a. HasCallStack => [a] -> a
head ([[Int]] -> [Int]) -> [[Int]] -> [Int]
forall a b. (a -> b) -> a -> b
$ ([Int] -> [Int] -> Ordering) -> [[Int]] -> [[Int]]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> ([Int] -> Int) -> [Int] -> [Int] -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum) [[Int]
cmpt, [Int]
invCmpt]

-------------------------------------------------------------------------------
-- Internal Helpers
-------------------------------------------------------------------------------

-- |Read a note name from string
readNoteName :: String -> NoteName
readNoteName :: String -> NoteName
readNoteName String
"C"  = NoteName
C
readNoteName String
"C#" = NoteName
C'
readNoteName String
"Db" = NoteName
Db
readNoteName String
"D"  = NoteName
D
readNoteName String
"D#" = NoteName
D'
readNoteName String
"Eb" = NoteName
Eb
readNoteName String
"E"  = NoteName
E
readNoteName String
"F"  = NoteName
F
readNoteName String
"F#" = NoteName
F'
readNoteName String
"Gb" = NoteName
Gb
readNoteName String
"G"  = NoteName
G
readNoteName String
"G#" = NoteName
G'
readNoteName String
"Ab" = NoteName
Ab
readNoteName String
"A"  = NoteName
A
readNoteName String
"A#" = NoteName
A'
readNoteName String
"Bb" = NoteName
Bb
readNoteName String
"B"  = NoteName
B
readNoteName String
s    = String -> NoteName
forall a. HasCallStack => String -> a
error (String -> NoteName) -> String -> NoteName
forall a b. (a -> b) -> a -> b
$ String
"readNoteName: unknown note name: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. Show a => a -> String
show String
s

-- Note: enharmFromNoteName is imported from Harmonic.Core.Pitch

-- |Zero-form for pitch classes
-- Subtracts the FIRST element (not minimum) then sorts, matching legacy behavior
-- |Normalize pitch class set to zero form by subtracting first element then sorting.
-- Examples:
--   [P 4, P 7, P 11] → [P 0, P 3, P 7]  (maj7 in root position)
--   [P 8, P 11, P 3] → [P 0, P 3, P 7]  (maj7 in 2nd inversion)
-- Used by all Cadence construction paths (DB, toCadence, fallback) for semantic consistency.
zeroFormPC :: [PitchClass] -> [PitchClass]
zeroFormPC :: [PitchClass] -> [PitchClass]
zeroFormPC [] = []
zeroFormPC xs :: [PitchClass]
xs@(P Int
first:[PitchClass]
_) = 
  [PitchClass] -> [PitchClass]
forall a. Ord a => [a] -> [a]
sort ([PitchClass] -> [PitchClass]) -> [PitchClass] -> [PitchClass]
forall a b. (a -> b) -> a -> b
$ (PitchClass -> PitchClass) -> [PitchClass] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map (\(P Int
n) -> Int -> PitchClass
P ((Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
first) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12)) [PitchClass]
xs

-- |Normalize pitches with respect to a fundamental
normalizeWithFund :: Int -> [Int] -> [Int]
normalizeWithFund :: Int -> [Int] -> [Int]
normalizeWithFund Int
fund [Int]
ps = 
  let ps' :: [Int]
ps' = (Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) [Int]
ps
      adjusted :: [Int]
adjusted = Int
fund Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort ((Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
fund Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) [Int]
ps')
  in [Int]
adjusted

-- |Simple possible triads generation (for chord construction)
possibleTriadsSimple :: (PitchClass -> NoteName) -> Int -> [Int] -> [[Int]]
possibleTriadsSimple :: (PitchClass -> NoteName) -> Int -> [Int] -> [[Int]]
possibleTriadsSimple PitchClass -> NoteName
_ Int
fund [Int]
ps =
  let fundPC :: Int
fundPC = Int
fund Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
      otherPCs :: [Int]
otherPCs = [Int] -> [Int]
forall a. Eq a => [a] -> [a]
List.nub ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ (Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
fundPC) ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ (Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) [Int]
ps
      pairs :: [[Int]]
pairs = [[Int
a, Int
b] | Int
a <- [Int]
otherPCs, Int
b <- [Int]
otherPCs, Int
a Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
b]
  in ([Int] -> [Int]) -> [[Int]] -> [[Int]]
forall a b. (a -> b) -> [a] -> [b]
map (Int
fundPC Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
:) [[Int]]
pairs

-- |Select most consonant option from a list of pitch sets.
-- Inline replica of Dissonance.mostConsonant (Layer B cannot import Layer C).
-- Includes perfect fifth bonus (-1) and degenerate set penalty (27).
mostConsonant :: [[Int]] -> [Int]
mostConsonant :: [[Int]] -> [Int]
mostConsonant [] = [Int
0, Int
4, Int
7]  -- Default to major triad
mostConsonant [[Int]]
xs = (Int, [Int]) -> [Int]
forall a b. (a, b) -> b
snd ((Int, [Int]) -> [Int])
-> ([(Int, [Int])] -> (Int, [Int])) -> [(Int, [Int])] -> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Int, [Int])] -> (Int, [Int])
forall a. HasCallStack => [a] -> a
head ([(Int, [Int])] -> (Int, [Int]))
-> ([(Int, [Int])] -> [(Int, [Int])])
-> [(Int, [Int])]
-> (Int, [Int])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Int, [Int]) -> (Int, [Int]) -> Ordering)
-> [(Int, [Int])] -> [(Int, [Int])]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> ((Int, [Int]) -> Int)
-> (Int, [Int])
-> (Int, [Int])
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Int, [Int]) -> Int
forall a b. (a, b) -> a
fst) ([(Int, [Int])] -> [Int]) -> [(Int, [Int])] -> [Int]
forall a b. (a -> b) -> a -> b
$ ([Int] -> (Int, [Int])) -> [[Int]] -> [(Int, [Int])]
forall a b. (a -> b) -> [a] -> [b]
map [Int] -> (Int, [Int])
forall {a}. Integral a => [a] -> (Int, [a])
dissonanceLevel [[Int]]
xs
  where
    dissonanceLevel :: [a] -> (Int, [a])
dissonanceLevel [a]
ys
      | [Int] -> Int -> Int
forall {a}. Eq a => [a] -> a -> Int
countElem [Int]
iVect Int
0 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
5 = (Int
27 :: Int, [a]
ys)
      | [a] -> Bool
forall {a}. Integral a => [a] -> Bool
hasPerfectFifth [a]
ys     = (Int
baseDiss Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, [a]
ys)
      | Bool
otherwise              = (Int
baseDiss, [a]
ys)
      where
        iVect :: [Int]
iVect    = [a] -> [Int]
forall {a}. Integral a => [a] -> [Int]
intervalVector [a]
ys
        baseDiss :: Int
baseDiss = [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (Int -> Int -> Int) -> [Int] -> [Int] -> [Int]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(*) [Int
16,Int
8,Int
4,Int
2,Int
1,Int
24] [Int]
iVect
    intervalVector :: [a] -> [Int]
intervalVector [a]
ys = [a -> [a] -> Int
forall {a}. Integral a => a -> [a] -> Int
countInterval a
i [a]
ys | a
i <- [a
1..a
6]]
    countInterval :: a -> [a] -> Int
countInterval a
i [a]
ys = [()] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [() | a
a <- [a]
ys, a
b <- [a]
ys, a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
b, ((a
b a -> a -> a
forall a. Num a => a -> a -> a
- a
a) a -> a -> a
forall a. Integral a => a -> a -> a
`mod` a
12) a -> [a] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [a
i, a
12a -> a -> a
forall a. Num a => a -> a -> a
-a
i]]
    countElem :: [a] -> a -> Int
countElem [a]
xs' a
x = [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ((a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
filter (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x) [a]
xs')
    hasPerfectFifth :: [a] -> Bool
hasPerfectFifth [] = Bool
False
    hasPerfectFifth (a
root:[a]
rest) =
      let p5 :: a
p5 = (a
root a -> a -> a
forall a. Num a => a -> a -> a
+ a
7) a -> a -> a
forall a. Integral a => a -> a -> a
`mod` a
12
      in (a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\a
x -> a
x a -> a -> a
forall a. Integral a => a -> a -> a
`mod` a
12 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
p5) [a]
rest

-- |Detect chord inversion by pattern matching against known inversion forms
-- Returns (root_note, inversion_suffix) where suffix is "", "_1stInv", or "_2ndInv"
-- Uses mathematical computation of root instead of index-based lookup
detectInversion :: (PitchClass -> NoteName) -> [Int] -> (NoteName, String)
detectInversion :: (PitchClass -> NoteName) -> [Int] -> (NoteName, String)
detectInversion PitchClass -> NoteName
enharm [Int]
xs
  | [Int] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
xs = (PitchClass -> NoteName
enharm (Int -> PitchClass
P Int
0), String
"")
  | [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
xs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
3 = (PitchClass -> NoteName
enharm (Int -> PitchClass
mkPitchClass ([Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int]
xs)), String
"")
  | Bool
otherwise =
    let pcs :: [PitchClass]
pcs = (Int -> PitchClass) -> [Int] -> [PitchClass]
forall a b. (a -> b) -> [a] -> [b]
map Int -> PitchClass
mkPitchClass [Int]
xs
        bass :: PitchClass
bass = Int -> PitchClass
mkPitchClass ([Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int]
xs)
        invs :: [[PitchClass]]
invs = [PitchClass] -> [[PitchClass]]
inversions [PitchClass]
pcs
        headInv :: [PitchClass]
headInv = [[PitchClass]] -> [PitchClass]
forall a. HasCallStack => [a] -> a
head [[PitchClass]]
invs
        -- Compute root from bass + interval offset based on pattern
        rootFromOffset :: Int -> NoteName
rootFromOffset Int
offset = PitchClass -> NoteName
enharm (PitchClass
bass PitchClass -> PitchClass -> PitchClass
forall a. Num a => a -> a -> a
+ Int -> PitchClass
P Int
offset)
    in case [PitchClass]
headInv of
      -- Root position major: root is bass
      [P Int
0, P Int
4, P Int
7] -> (Int -> NoteName
rootFromOffset Int
0, String
"")
      -- Root position minor: root is bass
      [P Int
0, P Int
3, P Int
7] -> (Int -> NoteName
rootFromOffset Int
0, String
"")
      -- 1st inversion major: [0,3,8] means root is 8 semitones above bass
      [P Int
0, P Int
3, P Int
8] -> (Int -> NoteName
rootFromOffset Int
8, String
"_1stInv")
      -- 1st inversion minor: [0,4,9] means root is 9 semitones above bass
      [P Int
0, P Int
4, P Int
9] -> (Int -> NoteName
rootFromOffset Int
9, String
"_1stInv")
      -- 2nd inversion major: [0,5,9] means root is 5 semitones above bass
      [P Int
0, P Int
5, P Int
9] -> (Int -> NoteName
rootFromOffset Int
5, String
"_2ndInv")
      -- 2nd inversion minor: [0,5,8] means root is 5 semitones above bass
      [P Int
0, P Int
5, P Int
8] -> (Int -> NoteName
rootFromOffset Int
5, String
"_2ndInv")
      -- Root position dim
      [P Int
0, P Int
3, P Int
6] -> (Int -> NoteName
rootFromOffset Int
0, String
"")
      -- 2nd inversion dim: root is 6 semitones above bass
      [P Int
0, P Int
6, P Int
9] -> (Int -> NoteName
rootFromOffset Int
6, String
"_2ndInv")
      -- 1st inversion dim: root is 9 semitones above bass
      [P Int
0, P Int
3, P Int
9] -> (Int -> NoteName
rootFromOffset Int
9, String
"_1stInv")
      -- Fallback: assume root position
      [PitchClass]
_ -> (Int -> NoteName
rootFromOffset Int
0, String
"")

-- |Check if a cadence is an inversion (1st or 2nd) based on zero-form intervals.
-- Patterns match those in @detectInversion@.
isInversion :: Cadence -> Bool
isInversion :: Cadence -> Bool
isInversion Cadence
cad = case Cadence -> [PitchClass]
cadenceIntervals Cadence
cad of
  [P Int
0, P Int
3, P Int
8]  -> Bool
True  -- 1st inversion major
  [P Int
0, P Int
4, P Int
9]  -> Bool
True  -- 1st inversion minor
  [P Int
0, P Int
5, P Int
9]  -> Bool
True  -- 2nd inversion major
  [P Int
0, P Int
5, P Int
8]  -> Bool
True  -- 2nd inversion minor
  [P Int
0, P Int
6, P Int
9]  -> Bool
True  -- 2nd inversion dim
  [P Int
0, P Int
3, P Int
9]  -> Bool
True  -- 1st inversion dim
  [PitchClass]
_                 -> Bool
False