packages feed

HarmTrace-0.4: MIR/HarmGram/MIR.hs

{-# LANGUAGE TemplateHaskell          #-}
{-# LANGUAGE TypeOperators            #-}
{-# LANGUAGE EmptyDataDecls           #-}
{-# LANGUAGE TypeSynonymInstances     #-}
{-# LANGUAGE FlexibleInstances        #-}
{-# LANGUAGE ScopedTypeVariables      #-}
{-# LANGUAGE MultiParamTypeClasses    #-}
{-# LANGUAGE TypeFamilies             #-}
{-# LANGUAGE UndecidableInstances     #-}
{-# LANGUAGE GADTs                    #-}
{-# LANGUAGE CPP                      #-}
{-# LANGUAGE DeriveDataTypeable       #-}

module MIR.HarmGram.MIR where

import MIR.HarmGram.TypeLevel

import MIR.HarmGram.Tokenizer hiding (D)
import Language.Haskell.TH.Syntax (Name)

import Data.Typeable

--------------------------------------------------------------------------------
-- Musical structure as a datatype
--------------------------------------------------------------------------------

-- High level structure
data Piece = Piece     [Phrase] 
           | Piece_min [PhraseMin] 
  deriving Typeable

-- The Prase level           
data Phrase     = PT Ton
                | PD Dom
  deriving Typeable
data PhraseMin  = PT_m TMin
                | PD_m DMin
  deriving Typeable
                
-- Harmonic categories for pieces in major keys
-- Tonic in major
data Ton  = T_2 (SD I MajClass)
          | Tbls_0 (Final I DomClass)
          | T_3 (Final I MajClass) (Final IV  MajClass) (Final I MajClass)
          | T_4 (Final I MajClass) (Final I   DimClass) (Final I MajClass)
  deriving Typeable

-- Dominant in major    
data Dom  = D_1 SDom Dom 
          | Dm_0 DMinBorrow 
          | D_2 (SD V DomClass)
          | D_3 (SD V MajClass)
          | D_4 (SD VII DimClass)
          | D_5 (Final V DomClass) (Final V DimClass) (Final V DomClass)   
  deriving Typeable

-- Subdominant in major          
data SDom = S_1  DiatV
          | Sbls_0 (SD IV DomClass) (SD I DomClass)
          | Sm_0 SMinBorrow
          | S_2 (SD II MinClass)
          | S_3 (SD IV MajClass)
          | S_4 (SD VI MinClass) -- maybe substitute by sec dom??
          | S_5 (SD III MinClass) (Final IV MajClass) 
          | S_6 (SD II DomClass) (Final II MinClass) -- pretty printing???
  deriving Typeable

-- account for diatonic succession          
data DiatV  = Vd_1 (SD III MinClass) (Final VI  MinClass)
            | Vd_2 (SD IV  MajClass) (Final VII MinClass)  
  deriving Typeable

-- Harmonic categories for pieces in minor keys
data TMin = Tm_2 (SD I MinClass)
          | Tm_3 (Final I MinClass) (Final IV  MinClass) (Final I MinClass)
          | T_0 TMajBorrow
  deriving Typeable

data TMajBorrow = 
            Tpar (SD IIIb MajClass)
  deriving Typeable
          
data DMin = Dm_1 SMin DMin
          | Dm_2 (SD V DomClass)
          | Dm_3 (SD V MajClass)      
          -- | Dm_4 (Final VIIb DomClass)   
          | Dm_5 (SD IIb  MajClass)   -- Neapolitan 
  deriving Typeable

-- Borrowings from minor in a major key
data DMinBorrow =      
            Dm_4' (Final VIIb DomClass)   
          | Dm_5' (SD IIb  MajClass)   -- Neapolitan 
  deriving Typeable
 
data SMin = Sm_1 DiatVm
          | Sm_2 (SD II MinClass)
          | Sm_3 (SD IV MinClass)
          | Sm_4 (SD VIb MajClass)
          | Sm_5 (SD II DomClass) (Final II MinClass) -- pretty printing???
  deriving Typeable
 
 -- Borrowings from minor in a major key
data SMinBorrow = 
            Sm_3' (SD IV MinClass)
  deriving Typeable

data DiatVm  = Vdm_1  (SD IIIb MajClass) (Final VIb MajClass)
             | Vdm_2  (SD IV  MinClass)  (Final VII DomClass)  
             -- | Vd_m2 (SD VI MajClass)  (Final II MinClass)
  deriving Typeable

         
-- Limit secondary dominants to a few levels
type SD deg clss = Base_SD deg clss T5

-- a type that can be substituted by its tritone sub and diminished 7b9
type TritMinVSub deg clss = Base_Final deg clss T2

-- A Scale degree that can only trnaslate to a surface chord
-- (or a dim chord transformation of a diminshed surface chord
type Final deg clss = Surface_Chord deg clss T4


-- Datatypes for clustering harmonic degrees
data Base_SD deg clss :: * -> * where
  Base_SD      :: Min5    deg clss  n           
               -> Base_SD deg clss (Su n)
  -- Rule for explaining perfect secondary dominants
  Cons_Vdom :: Base_SD (VDom deg) DomClass n -> Min5 deg clss n
               -> Base_SD deg clss (Su n)             
  deriving Typeable

-- One case only allowed (Tritone or Cons_Vmin)
type Min5 deg clss n = Base_Vmin deg clss n

data Base_Vmin deg clss :: * -> * where
  -- No minor fifth
  Base_Vmin :: TritMinVSub deg clss             
            -> Base_Vmin   deg clss (Su n)
  -- Minor fifth insertion
  Cons_Vmin :: Base_SD  (VMin deg) MinClass     n  -> TritMinVSub deg DomClass 
            -> Base_Vmin      deg  DomClass (Su n)
  deriving Typeable
            
            
data Base_Final deg :: * -> * -> * where
  -- Just a "normal", final degree. The Strings are the original input.
  Base_Final     :: Final deg clss -> Base_Final deg clss (Su n)
  -- Tritone substitution
  Final_Tritone  :: Base_Final (Tritone deg) DomClass n
                 -> Base_Final deg DomClass (Su n)   
  Final_Dim_Trit :: Base_Final (Tritone deg) DimClass n
                 -> Base_Final deg DomClass (Su n)     
  deriving Typeable         

-- Diminished tritone substitution accounting for diminished chord transistions
data Surface_Chord deg :: * -> * -> * where
  Surface_Chord  :: Degree -> [(Class, String)] 
                 -> Surface_Chord deg clss    (Su n)            
  Dim_Chord_Trns :: Surface_Chord (MinThird deg) DimClass n
                 -> Surface_Chord deg DimClass (Su n)  
  deriving Typeable    

--------------------------------------------------------------------------------
-- Type Level Scale Degrees
--------------------------------------------------------------------------------

-- Classes (at the type level)
data MajClass deriving Typeable
data MinClass deriving Typeable
data DomClass deriving Typeable
data DimClass deriving Typeable

-- Classes (at the value level)
data Class = Class ClassType Shorthand deriving Typeable

instance Show Class where show (Class ct sh) = show ct

data ClassType = MajClass | MinClass | DomClass | DimClass

instance Show ClassType where
  show (MajClass) = ""
  show (MinClass) = "m"
  show (DomClass) = "7"
  show (DimClass) = "0"

-- Degrees (at the type level)
data I deriving Typeable
data Ib deriving Typeable
data Is deriving Typeable
data II deriving Typeable
data IIb deriving Typeable
data IIs deriving Typeable
data III deriving Typeable
data IIIb deriving Typeable
data IIIs deriving Typeable
data IV deriving Typeable
data IVb deriving Typeable
data IVs deriving Typeable
data V deriving Typeable
data Vb deriving Typeable
data Vs deriving Typeable
data VI deriving Typeable
data VIb deriving Typeable
data VIs deriving Typeable
data VII deriving Typeable
data VIIb deriving Typeable
data VIIs deriving Typeable

-- Used when we don't want to consider certain possibilities
data Imp deriving Typeable

-- Degrees at the value level are in Tokenizer
-- Type to value conversions
class ToClass clss where
  toClass :: clss -> ClassType

instance ToClass MajClass where toClass _ = MajClass
instance ToClass MinClass where toClass _ = MinClass
instance ToClass DomClass where toClass _ = DomClass
instance ToClass DimClass where toClass _ = DimClass

-- The class doesn't really matter, since the degree will be impossible to parse
instance ToClass Imp where toClass _ = DimClass

class ToDegree deg where
  toDegree :: deg -> Degree

instance ToDegree I     where toDegree _ = Degree Nothing 1
instance ToDegree II    where toDegree _ = Degree Nothing 2
instance ToDegree III   where toDegree _ = Degree Nothing 3
instance ToDegree IV    where toDegree _ = Degree Nothing 4
instance ToDegree V     where toDegree _ = Degree Nothing 5
instance ToDegree VI    where toDegree _ = Degree Nothing 6
instance ToDegree VII   where toDegree _ = Degree Nothing 7
instance ToDegree Ib    where toDegree _ = Degree (Just Fl) 1
instance ToDegree IIb   where toDegree _ = Degree (Just Fl) 2
instance ToDegree IIIb  where toDegree _ = Degree (Just Fl) 3
instance ToDegree IVb   where toDegree _ = Degree (Just Fl) 4
instance ToDegree Vb    where toDegree _ = Degree (Just Fl) 5
instance ToDegree VIb   where toDegree _ = Degree (Just Fl) 6
instance ToDegree VIIb  where toDegree _ = Degree (Just Fl) 7
instance ToDegree IIs   where toDegree _ = Degree (Just Sh) 2
instance ToDegree IIIs  where toDegree _ = Degree (Just Sh) 3
instance ToDegree IVs   where toDegree _ = Degree (Just Sh) 4
instance ToDegree Vs    where toDegree _ = Degree (Just Sh) 5
instance ToDegree VIs   where toDegree _ = Degree (Just Sh) 6
instance ToDegree VIIs  where toDegree _ = Degree (Just Sh) 7

-- Can't ever parse degree 42 (TODO: what about error correction?...)
instance ToDegree Imp where toDegree _ = Degree Nothing 42


--------------------------------------------------------------------------------
-- Type Families for Relative Scale Degrees
--------------------------------------------------------------------------------
-- Perfect fifths (class is always Dom)
-- See http://en.wikipedia.org/wiki/Circle_of_fifths
type family VDom deg :: *

type instance VDom I     = Imp -- interferes with dom 
type instance VDom IIb   = VIb
type instance VDom II    = VI 
type instance VDom IIIb  = VIIb -- interferes with Dm_3
type instance VDom III   = VII
type instance VDom IV    = I
type instance VDom IVs   = IIb
type instance VDom V     = II -- interferes with Sm_1
type instance VDom VIb   = IIIb
type instance VDom VI    = III
type instance VDom VIIb  = IV
type instance VDom VII   = IVs
type instance VDom Imp   = Imp

-- Perfect fifths for the minor case (this is an additional
-- type family to controll the reduction of ambiguities
-- specifically in the minor case)
type family VMin deg :: *
type instance VMin I     = V 
type instance VMin IIb   = VIb
type instance VMin II    = VI --Imp -- VI interferes with sub 
type instance VMin IIIb  = VIIb
type instance VMin III   = VII
type instance VMin IV    = I
type instance VMin IVs   = IIb
type instance VMin V     = Imp -- II interferes with sub
type instance VMin VIb   = IIIb
type instance VMin VI    = III
type instance VMin VIIb  = IV
type instance VMin VII   = IVs
type instance VMin Imp   = Imp

-- The tritone substitution
-- See http://en.wikipedia.org/wiki/Tritone_substitution
type family Tritone deg :: *
type instance Tritone I     = IVs
type instance Tritone IVs   = I

-- type instance Tritone Is    = V
type instance Tritone IIb   = V
type instance Tritone V     = IIb 

type instance Tritone II    = VIb
type instance Tritone VIb   = II

type instance Tritone IIIb  = VI
type instance Tritone VI    = IIIb

type instance Tritone III   = VIIb -- Interferes with VIIb from minor
type instance Tritone VIIb  = III 

type instance Tritone IV    = VII
type instance Tritone VII   = IV

type instance Tritone Imp   = Imp


type family MinThird deg :: *
type instance MinThird I     = IIIb 
type instance MinThird IIb   = III
type instance MinThird II    = IV
type instance MinThird IIIb  = IVs
type instance MinThird III   = V
type instance MinThird IV    = VIb
type instance MinThird IVs   = VI
type instance MinThird V     = VIIb 
type instance MinThird VIb   = VII
type instance MinThird VI    = I
type instance MinThird VIIb  = IIb
type instance MinThird VII   = II
type instance MinThird Imp   = Imp

-- Belongs in Instances, but needs to be here due to staging restrictions
allTypes :: [Name]
allTypes = [ ''Phrase, ''PhraseMin, ''TMin, ''Ton 
           , ''Dom, ''DMinBorrow, ''SDom, ''DMin, ''DiatV, ''SMin, ''DiatVm 
           , ''SMinBorrow, ''TMajBorrow
           ]