------------------------------------------------------------------------------------ -- | -- Copyright : (c) Hans Hoglund 2012 -- -- License : BSD-style -- -- Maintainer : hans@hanshoglund.se -- Stability : experimental -- Portability : non-portable (TF,GNTD) -- -- Provides a representation of pitch as defined in Common Music Theory (CMT). -- ------------------------------------------------------------------------------------- module Music.Pitch.Common ( -- * Enharmonic representation -- ** Octaves Octaves, HasOctaves(..), -- ** Steps Steps, HasSteps(..), -- ** Semitones Semitones, HasSemitones(..), semitone, tone, ditone, tritone, isSemitone, isTone, isTritone, -- ** Enharmonic equivalence (=:=), (/:=), -- * Pitches -- ** Name type Name(..), -- ** Accidental type Accidental, doubleFlat, flat, natural, sharp, doubleSharp, -- *** Inspecting accidentals isNatural, isSharpened, isFlattened, isStandard, -- ** Pitch type Pitch, pitch, name, accidental, asPitch, -- module Music.Pitch.Common.Name, -- module Music.Pitch.Common.Accidental, -- module Music.Pitch.Common.Pitch, -- * Intervals -- ** Number type Number, HasNumber(..), unison, prime, second, third, fourth, fifth, sixth, seventh, octave, ninth, tenth, twelfth, duodecim, thirteenth, fourteenth, fifteenth, -- ** Quality type Quality(..), HasQuality(..), invertQuality, isPerfect, isMajor, isMinor, isAugmented, isDiminished, -- ** Interval type Interval, -- *** Creating intervals interval, perfect, major, minor, augmented, diminished, doublyAugmented, doublyDiminished, asInterval, -- *** Inspecting intervals isNegative, isPositive, isNonNegative, isPerfectUnison, isStep, isLeap, -- *** Simple and compound intervals isSimple, isCompound, separate, simple, -- *** Inversion invert, -- module Music.Pitch.Common.Number, -- module Music.Pitch.Common.Quality, -- module Music.Pitch.Common.Interval, -- * Miscellaneous module Music.Pitch.Common.Spell, module Music.Pitch.Common.Harmony, ) where import Data.Maybe import Data.Either import Data.Semigroup import Data.VectorSpace import Data.AffineSpace import Control.Monad import Control.Applicative import qualified Data.List as List import Music.Pitch.Absolute import Music.Pitch.Literal import Music.Pitch.Common.Pitch import Music.Pitch.Common.Interval import Music.Pitch.Common.Semitones import Music.Pitch.Common.Spell import Music.Pitch.Common.Harmony {- Semitones is the smallest musical unit (Semitones in Western music) The `semitones` function retrieves the number of Semitones in a pitch, for example semitones :: Interval -> Semitones semitones major third = 4 Note that semitones is surjetive. We can define a non-deterministic function `spellings` spellings :: Semitones -> [Interval] spellings 4 = [majorThird, diminishedFourth] Law map semitones (spellings a) = replicate n a for all n > 0 Lemma map semitones (spellings a) isHemitonic [1,2,2] = True isHemitonic [2,2,2] = False isCohemitonic [1,1,2] = True isCohemitonic [1,2,1] = False isTritonic ... A Scale is a [Semitones], for example [2,2,1,2,2,2,1] From this we can derive [2,4,5,7,9,11,12] A Scale is a function (Number -> Interval) A Scale is a function (Number -> Semitones) -- TODO simplify etc isMelodicDissonance :: Interval -> Bool "Post-tonal" Messiaen mode1 = [2,2,2,2,2] mode2 = [1,2, 1,2, 1,2, 1,2] mode3 = [2,1,1, 2,1,1, 2,1,1] mode4 = [1,1,3,1, 1,1,3,1] mode5 = [1,4,1, 1,4,1] mode6 = [2,2,1,1, 2,2,1,1] mode7 = [1,1,1,2,1, 1,1,1,2,1] - Old stuff> -- Semitone is an enumerated associated type type family Semitone a :: * type family Alteration a :: * -- A scale is a function :: Semitone a -> a newtype Scale a = Scale { getScale :: [Semitone a] } -- Eq, Show semitone :: Scale a -> Semitone a -> a semitone = undefined semitone (Scale xs) p = xs !! (fromIntegral p `mod` length xs) fromSemitone :: (Num a, Ord a, Integral b, Num c) => Scale a -> b -> c fromSemitone (Scale xs) p = fromIntegral $ fromMaybe (length xs - 1) $ List.findIndex (>= fromIntegral p) xs scaleFromSemitones :: Num a => [a] -> Scale a scaleFromSemitones = Scale . accum where accum = snd . List.mapAccumL add 0 add a x = (a + x, a + x) -- numberOfSemitones :: Scale a -> Int numberOfSemitones = length . getScale major :: Num a => Scale a major = scaleFromSemitones [0,2,2,1,2,2,2,1] naturalMinor :: Num a => Scale a naturalMinor = scaleFromSemitones [0,2,1,2,2,1,2,2] harmonicMinor :: Num a => Scale a harmonicMinor = scaleFromSemitones [0,2,1,2,2,1,3,1] -} -- or' :: (t -> Bool) -> (t -> Bool) -> t -> Bool -- or' p q x = p x || q x -- replicate' n = replicate (fromIntegral n)