{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving #-} module Music.Pitch.Relative.Quality ( -- * Augmentable class Augmentable(..), -- * Quality Quality(..), HasQuality(..), -- invertQuality, isPerfect, isMajor, isMinor, isAugmented, isDiminished, -- TODO diffToQuality, qualityToDiff, invertQuality, replicate', ) where -- | -- Class of types that can be augmented. -- class Augmentable a where -- | -- Increase the size of this interval by one. -- augment :: a -> a -- | -- Decrease the size of this interval by one. -- diminish :: a -> a -- | -- Interval quality is either perfect, major, minor, augmented, and -- diminished. This representation allows for an arbitrary number of -- augmentation or diminishions, so /augmented/ is represented by @Augmented -- 1@, /doubly augmented/ by @Augmented 2@ and so on. -- -- The quality of a compound interval is the quality of the simple interval on -- which it is based. -- data Quality = Major | Minor | Perfect | Augmented Integer | Diminished Integer deriving (Eq, Ord) instance Show Quality where show Major = "_M" show Minor = "m" show Perfect = "_P" show (Augmented n) = "_" ++ replicate' n 'A' show (Diminished n) = replicate' n 'd' instance HasQuality Quality where quality = id -- TODO this instance should not be used -- instance Augmentable Quality where -- augment = go -- where -- go (Diminished 0) = Augmented n -- not unique! -- go (Diminished n) = Augmented n -- go Minor = Major -- go Major = Augmented 1 -- go Perfect = Augmented 1 -- go (Augmented n) = Diminished (n) class HasQuality a where quality :: a -> Quality invertQuality :: Quality -> Quality invertQuality = go where go Major = Minor go Minor = Major go Perfect = Perfect go (Augmented n) = Diminished n go (Diminished n) = Augmented n -- | -- Returns whether the given quality is perfect. -- isPerfect :: HasQuality a => a -> Bool isPerfect a = case quality a of { Perfect -> True ; _ -> False } -- | -- Returns whether the given quality is major. -- isMajor :: HasQuality a => a -> Bool isMajor a = case quality a of { Major -> True ; _ -> False } -- | -- Returns whether the given quality is minor. -- isMinor :: HasQuality a => a -> Bool isMinor a = case quality a of { Minor -> True ; _ -> False } -- | -- Returns whether the given quality is /augmented/ (including double augmented etc). -- isAugmented :: HasQuality a => a -> Bool isAugmented a = case quality a of { Augmented _ -> True ; _ -> False } -- | -- Returns whether the given quality is /diminished/ (including double diminished etc). -- isDiminished :: HasQuality a => a -> Bool isDiminished a = case quality a of { Diminished _ -> True ; _ -> False } -- | -- Convert an offset to a quality. -- -- This is different for perfect and imperfect interals: -- -- Imperfect Perfect -- === === -- -3 dd ddd -- -2 d dd -- -1 m d -- 0 M P -- 1 a a -- 2 aa aa -- diffToQuality :: Bool -> Int -> Quality diffToQuality = go where go True 0 = Perfect go True n = if n > 0 then Augmented (fromIntegral n) else Diminished (fromIntegral $ negate n) go False 0 = Major go False (-1) = Minor go False n = if n > 0 then Augmented (fromIntegral n) else Diminished (fromIntegral $ negate $ n + 1) qualityToDiff :: Bool -> Quality -> Int qualityToDiff perfect = go where go (Diminished n) = fromIntegral $ negate $ if perfect then n else n + 1 go Minor = fromIntegral $ -1 go Perfect = fromIntegral $ 0 go Major = fromIntegral $ 0 go (Augmented n) = fromIntegral $ n replicate' n = replicate (fromIntegral n)