packages feed

music-pitch 1.2 → 1.3

raw patch · 12 files changed

+1252/−71 lines, 12 filesdep +music-pitch-literaldep +vector-spacePVP ok

version bump matches the API change (PVP)

Dependencies added: music-pitch-literal, vector-space

API changes (from Hackage documentation)

- Music.Pitch.Absolute: Cents :: Frequency -> Cents
- Music.Pitch.Absolute: Fifths :: Frequency -> Fifths
- Music.Pitch.Absolute: Frequency :: Double -> Frequency
- Music.Pitch.Absolute: Octaves :: Frequency -> Octaves
- Music.Pitch.Absolute: class HasFrequence a
- Music.Pitch.Absolute: getCents :: Cents -> Frequency
- Music.Pitch.Absolute: getFifths :: Fifths -> Frequency
- Music.Pitch.Absolute: getFrequency :: Frequency -> Double
- Music.Pitch.Absolute: getOctaves :: Octaves -> Frequency
- Music.Pitch.Absolute: instance Enum Frequency
- Music.Pitch.Absolute: instance Eq Frequency
- Music.Pitch.Absolute: instance Floating Frequency
- Music.Pitch.Absolute: instance Fractional Frequency
- Music.Pitch.Absolute: instance Num Frequency
- Music.Pitch.Absolute: instance Ord Frequency
- Music.Pitch.Absolute: instance Show Frequency
- Music.Pitch.Absolute: newtype Cents
- Music.Pitch.Absolute: newtype Fifths
- Music.Pitch.Absolute: newtype Frequency
- Music.Pitch.Absolute: newtype Octaves
- Music.Pitch.Absolute: octaves :: HasFrequence a => a -> Octaves
+ Music.Pitch.Absolute: Hertz :: Double -> Hertz
+ Music.Pitch.Absolute: class HasFrequency a
+ Music.Pitch.Absolute: data Cents
+ Music.Pitch.Absolute: data Fifths
+ Music.Pitch.Absolute: getHertz :: Hertz -> Double
+ Music.Pitch.Absolute: instance Enum Hertz
+ Music.Pitch.Absolute: instance Eq Hertz
+ Music.Pitch.Absolute: instance Floating Hertz
+ Music.Pitch.Absolute: instance Fractional Hertz
+ Music.Pitch.Absolute: instance HasFrequency Cents
+ Music.Pitch.Absolute: instance HasFrequency Fifths
+ Music.Pitch.Absolute: instance HasFrequency Hertz
+ Music.Pitch.Absolute: instance HasFrequency Octaves
+ Music.Pitch.Absolute: instance Monoid Cents
+ Music.Pitch.Absolute: instance Monoid Fifths
+ Music.Pitch.Absolute: instance Monoid Hertz
+ Music.Pitch.Absolute: instance Monoid Octaves
+ Music.Pitch.Absolute: instance Num Hertz
+ Music.Pitch.Absolute: instance Ord Hertz
+ Music.Pitch.Absolute: instance Read Cents
+ Music.Pitch.Absolute: instance Read Fifths
+ Music.Pitch.Absolute: instance Read Hertz
+ Music.Pitch.Absolute: instance Read Octaves
+ Music.Pitch.Absolute: instance Real Cents
+ Music.Pitch.Absolute: instance Real Fifths
+ Music.Pitch.Absolute: instance Real Hertz
+ Music.Pitch.Absolute: instance Real Octaves
+ Music.Pitch.Absolute: instance RealFrac Cents
+ Music.Pitch.Absolute: instance RealFrac Fifths
+ Music.Pitch.Absolute: instance RealFrac Hertz
+ Music.Pitch.Absolute: instance RealFrac Octaves
+ Music.Pitch.Absolute: instance Semigroup Cents
+ Music.Pitch.Absolute: instance Semigroup Fifths
+ Music.Pitch.Absolute: instance Semigroup Hertz
+ Music.Pitch.Absolute: instance Semigroup Octaves
+ Music.Pitch.Absolute: instance Show Hertz
+ Music.Pitch.Absolute: newtype Hertz
+ Music.Pitch.Intonation: pure :: Integral a => Intonation a
+ Music.Pitch.Intonation: pythagorean :: Integral a => Intonation a
+ Music.Pitch.Intonation: twelveToneEqual :: Integral a => Intonation a
+ Music.Pitch.Intonation: type Intonation a = a -> Hertz
+ Music.Pitch.Relative.Accidental: class Alterable a
+ Music.Pitch.Relative.Accidental: data Accidental
+ Music.Pitch.Relative.Accidental: doubleFlat :: Accidental
+ Music.Pitch.Relative.Accidental: doubleSharp :: Accidental
+ Music.Pitch.Relative.Accidental: flat :: Accidental
+ Music.Pitch.Relative.Accidental: flatten :: Alterable a => a -> a
+ Music.Pitch.Relative.Accidental: instance (IsPitch a, Alterable a) => IsPitch (Accidental -> a)
+ Music.Pitch.Relative.Accidental: instance Alterable Accidental
+ Music.Pitch.Relative.Accidental: instance Alterable Double
+ Music.Pitch.Relative.Accidental: instance Alterable Integer
+ Music.Pitch.Relative.Accidental: instance Enum Accidental
+ Music.Pitch.Relative.Accidental: instance Eq Accidental
+ Music.Pitch.Relative.Accidental: instance Integral Accidental
+ Music.Pitch.Relative.Accidental: instance Num Accidental
+ Music.Pitch.Relative.Accidental: instance Ord Accidental
+ Music.Pitch.Relative.Accidental: instance Real Accidental
+ Music.Pitch.Relative.Accidental: instance Show Accidental
+ Music.Pitch.Relative.Accidental: natural :: Accidental
+ Music.Pitch.Relative.Accidental: sharp :: Accidental
+ Music.Pitch.Relative.Accidental: sharpen :: Alterable a => a -> a
+ Music.Pitch.Relative.Interval: _A1 :: Interval
+ Music.Pitch.Relative.Interval: _A2 :: Interval
+ Music.Pitch.Relative.Interval: _A3 :: Interval
+ Music.Pitch.Relative.Interval: _A4 :: Interval
+ Music.Pitch.Relative.Interval: _A5 :: Interval
+ Music.Pitch.Relative.Interval: _A6 :: Interval
+ Music.Pitch.Relative.Interval: _A7 :: Interval
+ Music.Pitch.Relative.Interval: _A8 :: Interval
+ Music.Pitch.Relative.Interval: _M2 :: Interval
+ Music.Pitch.Relative.Interval: _M3 :: Interval
+ Music.Pitch.Relative.Interval: _M6 :: Interval
+ Music.Pitch.Relative.Interval: _M7 :: Interval
+ Music.Pitch.Relative.Interval: _P1 :: Interval
+ Music.Pitch.Relative.Interval: _P4 :: Interval
+ Music.Pitch.Relative.Interval: _P5 :: Interval
+ Music.Pitch.Relative.Interval: _P8 :: Interval
+ Music.Pitch.Relative.Interval: augmented :: Number -> Interval
+ Music.Pitch.Relative.Interval: d1 :: Interval
+ Music.Pitch.Relative.Interval: d2 :: Interval
+ Music.Pitch.Relative.Interval: d3 :: Interval
+ Music.Pitch.Relative.Interval: d4 :: Interval
+ Music.Pitch.Relative.Interval: d5 :: Interval
+ Music.Pitch.Relative.Interval: d6 :: Interval
+ Music.Pitch.Relative.Interval: d7 :: Interval
+ Music.Pitch.Relative.Interval: d8 :: Interval
+ Music.Pitch.Relative.Interval: data Interval
+ Music.Pitch.Relative.Interval: diminished :: Number -> Interval
+ Music.Pitch.Relative.Interval: doublyAugmented :: Number -> Interval
+ Music.Pitch.Relative.Interval: doublyDiminished :: Number -> Interval
+ Music.Pitch.Relative.Interval: flats :: Semitones -> Number
+ Music.Pitch.Relative.Interval: instance AdditiveGroup Interval
+ Music.Pitch.Relative.Interval: instance Augmentable Interval
+ Music.Pitch.Relative.Interval: instance Eq Interval
+ Music.Pitch.Relative.Interval: instance HasOctaves Interval
+ Music.Pitch.Relative.Interval: instance HasQuality Interval
+ Music.Pitch.Relative.Interval: instance HasSemitones Interval
+ Music.Pitch.Relative.Interval: instance HasSteps Interval
+ Music.Pitch.Relative.Interval: instance Monoid Interval
+ Music.Pitch.Relative.Interval: instance Num Interval
+ Music.Pitch.Relative.Interval: instance Ord Interval
+ Music.Pitch.Relative.Interval: instance Semigroup Interval
+ Music.Pitch.Relative.Interval: instance Show Interval
+ Music.Pitch.Relative.Interval: instance VectorSpace Interval
+ Music.Pitch.Relative.Interval: interval :: Quality -> Number -> Interval
+ Music.Pitch.Relative.Interval: interval' :: Int -> Int -> Interval
+ Music.Pitch.Relative.Interval: intervalDiff :: Interval -> Int
+ Music.Pitch.Relative.Interval: invert :: Interval -> Interval
+ Music.Pitch.Relative.Interval: isCompound :: Interval -> Bool
+ Music.Pitch.Relative.Interval: isNegative :: Interval -> Bool
+ Music.Pitch.Relative.Interval: isPositive :: Interval -> Bool
+ Music.Pitch.Relative.Interval: isSimple :: Interval -> Bool
+ Music.Pitch.Relative.Interval: m2 :: Interval
+ Music.Pitch.Relative.Interval: m3 :: Interval
+ Music.Pitch.Relative.Interval: m6 :: Interval
+ Music.Pitch.Relative.Interval: m7 :: Interval
+ Music.Pitch.Relative.Interval: major :: Number -> Interval
+ Music.Pitch.Relative.Interval: minor :: Number -> Interval
+ Music.Pitch.Relative.Interval: number :: Interval -> Number
+ Music.Pitch.Relative.Interval: octave :: Number
+ Music.Pitch.Relative.Interval: perfect :: Number -> Interval
+ Music.Pitch.Relative.Interval: separate :: Interval -> (Octaves, Interval)
+ Music.Pitch.Relative.Interval: sharps :: Semitones -> Number
+ Music.Pitch.Relative.Interval: simple :: Interval -> Interval
+ Music.Pitch.Relative.Interval: spell :: HasSemitones a => Spelling -> a -> Interval
+ Music.Pitch.Relative.Interval: type Spelling = Semitones -> Number
+ Music.Pitch.Relative.Name: A :: Name
+ Music.Pitch.Relative.Name: B :: Name
+ Music.Pitch.Relative.Name: C :: Name
+ Music.Pitch.Relative.Name: D :: Name
+ Music.Pitch.Relative.Name: E :: Name
+ Music.Pitch.Relative.Name: F :: Name
+ Music.Pitch.Relative.Name: G :: Name
+ Music.Pitch.Relative.Name: data Name
+ Music.Pitch.Relative.Name: instance Enum Name
+ Music.Pitch.Relative.Name: instance Eq Name
+ Music.Pitch.Relative.Name: instance Ord Name
+ Music.Pitch.Relative.Name: instance Show Name
+ Music.Pitch.Relative.Number: data Number
+ Music.Pitch.Relative.Number: fifth :: Number
+ Music.Pitch.Relative.Number: fourth :: Number
+ Music.Pitch.Relative.Number: instance Enum Number
+ Music.Pitch.Relative.Number: instance Eq Number
+ Music.Pitch.Relative.Number: instance Integral Number
+ Music.Pitch.Relative.Number: instance Num Number
+ Music.Pitch.Relative.Number: instance Ord Number
+ Music.Pitch.Relative.Number: instance Real Number
+ Music.Pitch.Relative.Number: instance Show Number
+ Music.Pitch.Relative.Number: octave :: Number
+ Music.Pitch.Relative.Number: prime :: Number
+ Music.Pitch.Relative.Number: second :: Number
+ Music.Pitch.Relative.Number: seventh :: Number
+ Music.Pitch.Relative.Number: sixth :: Number
+ Music.Pitch.Relative.Number: third :: Number
+ Music.Pitch.Relative.Number: unison :: Number
+ Music.Pitch.Relative.Pitch: accidental :: Pitch -> Accidental
+ Music.Pitch.Relative.Pitch: asPitch :: Pitch -> Pitch
+ Music.Pitch.Relative.Pitch: data Pitch
+ Music.Pitch.Relative.Pitch: instance AffineSpace Pitch
+ Music.Pitch.Relative.Pitch: instance Alterable Pitch
+ Music.Pitch.Relative.Pitch: instance Eq Pitch
+ Music.Pitch.Relative.Pitch: instance HasOctaves Pitch
+ Music.Pitch.Relative.Pitch: instance HasSemitones Pitch
+ Music.Pitch.Relative.Pitch: instance HasSteps Pitch
+ Music.Pitch.Relative.Pitch: instance IsPitch Pitch
+ Music.Pitch.Relative.Pitch: instance Num Pitch
+ Music.Pitch.Relative.Pitch: instance Ord Pitch
+ Music.Pitch.Relative.Pitch: instance Show Pitch
+ Music.Pitch.Relative.Pitch: name :: Pitch -> Name
+ Music.Pitch.Relative.Pitch: pitch :: Name -> Accidental -> Pitch
+ Music.Pitch.Relative.Quality: Augmented :: Integer -> Quality
+ Music.Pitch.Relative.Quality: Diminished :: Integer -> Quality
+ Music.Pitch.Relative.Quality: Major :: Quality
+ Music.Pitch.Relative.Quality: Minor :: Quality
+ Music.Pitch.Relative.Quality: Perfect :: Quality
+ Music.Pitch.Relative.Quality: augment :: Augmentable a => a -> a
+ Music.Pitch.Relative.Quality: class Augmentable a
+ Music.Pitch.Relative.Quality: class HasQuality a
+ Music.Pitch.Relative.Quality: data Quality
+ Music.Pitch.Relative.Quality: diffToQuality :: Bool -> Int -> Quality
+ Music.Pitch.Relative.Quality: diminish :: Augmentable a => a -> a
+ Music.Pitch.Relative.Quality: instance Eq Quality
+ Music.Pitch.Relative.Quality: instance HasQuality Quality
+ Music.Pitch.Relative.Quality: instance Ord Quality
+ Music.Pitch.Relative.Quality: instance Show Quality
+ Music.Pitch.Relative.Quality: invertQuality :: Quality -> Quality
+ Music.Pitch.Relative.Quality: isAugmented :: HasQuality a => a -> Bool
+ Music.Pitch.Relative.Quality: isDiminished :: HasQuality a => a -> Bool
+ Music.Pitch.Relative.Quality: isMajor :: HasQuality a => a -> Bool
+ Music.Pitch.Relative.Quality: isMinor :: HasQuality a => a -> Bool
+ Music.Pitch.Relative.Quality: isPerfect :: HasQuality a => a -> Bool
+ Music.Pitch.Relative.Quality: quality :: HasQuality a => a -> Quality
+ Music.Pitch.Relative.Quality: qualityToDiff :: Bool -> Quality -> Int
+ Music.Pitch.Relative.Quality: replicate' :: Integral a1 => a1 -> a -> [a]
+ Music.Pitch.Relative.Semitones: (/:=) :: HasSemitones a => a -> a -> Bool
+ Music.Pitch.Relative.Semitones: (=:=) :: HasSemitones a => a -> a -> Bool
+ Music.Pitch.Relative.Semitones: class HasOctaves a
+ Music.Pitch.Relative.Semitones: class HasSemitones a
+ Music.Pitch.Relative.Semitones: class HasSteps a
+ Music.Pitch.Relative.Semitones: data Octaves
+ Music.Pitch.Relative.Semitones: data Semitones
+ Music.Pitch.Relative.Semitones: data Steps
+ Music.Pitch.Relative.Semitones: ditone :: Semitones
+ Music.Pitch.Relative.Semitones: instance Enum Octaves
+ Music.Pitch.Relative.Semitones: instance Enum Semitones
+ Music.Pitch.Relative.Semitones: instance Enum Steps
+ Music.Pitch.Relative.Semitones: instance Eq Octaves
+ Music.Pitch.Relative.Semitones: instance Eq Semitones
+ Music.Pitch.Relative.Semitones: instance Eq Steps
+ Music.Pitch.Relative.Semitones: instance HasOctaves Octaves
+ Music.Pitch.Relative.Semitones: instance HasSemitones Semitones
+ Music.Pitch.Relative.Semitones: instance HasSteps Steps
+ Music.Pitch.Relative.Semitones: instance Integral Octaves
+ Music.Pitch.Relative.Semitones: instance Integral Semitones
+ Music.Pitch.Relative.Semitones: instance Integral Steps
+ Music.Pitch.Relative.Semitones: instance Num Octaves
+ Music.Pitch.Relative.Semitones: instance Num Semitones
+ Music.Pitch.Relative.Semitones: instance Num Steps
+ Music.Pitch.Relative.Semitones: instance Ord Octaves
+ Music.Pitch.Relative.Semitones: instance Ord Semitones
+ Music.Pitch.Relative.Semitones: instance Ord Steps
+ Music.Pitch.Relative.Semitones: instance Real Octaves
+ Music.Pitch.Relative.Semitones: instance Real Semitones
+ Music.Pitch.Relative.Semitones: instance Real Steps
+ Music.Pitch.Relative.Semitones: instance Show Octaves
+ Music.Pitch.Relative.Semitones: instance Show Semitones
+ Music.Pitch.Relative.Semitones: instance Show Steps
+ Music.Pitch.Relative.Semitones: isSemitone :: HasSemitones a => a -> Bool
+ Music.Pitch.Relative.Semitones: isTone :: HasSemitones a => a -> Bool
+ Music.Pitch.Relative.Semitones: isTritone :: HasSemitones a => a -> Bool
+ Music.Pitch.Relative.Semitones: octaves :: HasOctaves a => a -> Octaves
+ Music.Pitch.Relative.Semitones: semitone :: Semitones
+ Music.Pitch.Relative.Semitones: semitones :: HasSemitones a => a -> Semitones
+ Music.Pitch.Relative.Semitones: steps :: HasSteps a => a -> Steps
+ Music.Pitch.Relative.Semitones: tone :: Semitones
+ Music.Pitch.Relative.Semitones: tritone :: Semitones
- Music.Pitch.Absolute: cents :: HasFrequence a => a -> Cents
+ Music.Pitch.Absolute: cents :: HasFrequency a => a -> Cents
- Music.Pitch.Absolute: fifths :: HasFrequence a => a -> Fifths
+ Music.Pitch.Absolute: fifths :: HasFrequency a => a -> Fifths
- Music.Pitch.Absolute: frequency :: HasFrequence a => a -> Frequency
+ Music.Pitch.Absolute: frequency :: HasFrequency a => a -> Hertz

Files

music-pitch.cabal view
@@ -1,6 +1,6 @@  name:               music-pitch-version:            1.2+version:            1.3 cabal-version:      >= 1.2 author:             Hans Hoglund maintainer:         Hans Hoglund@@ -14,7 +14,7 @@ description:      Abstract representation of musical pitch.     -    This library is part of the Haskell Music Suite, see <http://musicsuite.github.com>.+    This library is part of the Music Suite        , see <http://musicsuite.github.com>.  library                         build-depends: @@ -23,11 +23,20 @@         time,         random,         semigroups,-        semigroupoids+        semigroupoids,+        music-pitch-literal,+        vector-space      hs-source-dirs: src     exposed-modules:         Music.Pitch         Music.Pitch.Absolute         Music.Pitch.Relative+        Music.Pitch.Relative.Accidental+        Music.Pitch.Relative.Interval+        Music.Pitch.Relative.Name+        Music.Pitch.Relative.Number+        Music.Pitch.Relative.Pitch+        Music.Pitch.Relative.Quality+        Music.Pitch.Relative.Semitones         Music.Pitch.Intonation
src/Music/Pitch.hs view
@@ -13,13 +13,13 @@ -- ------------------------------------------------------------------------------------- -module Music.Pitch -- (--- )-where+module Music.Pitch (+        module Music.Pitch.Absolute,+        module Music.Pitch.Relative,+        module Music.Pitch.Literal+  ) where -import Data.Maybe-import Data.Either-import Data.Semigroup-import Control.Monad-import Control.Applicative+import Music.Pitch.Absolute+import Music.Pitch.Relative+import Music.Pitch.Literal 
src/Music/Pitch/Absolute.hs view
@@ -12,13 +12,23 @@ -- Stability   : experimental -- Portability : portable ----- Provides overloaded pitch literals.+-- Absolute pitch representation.+-- +-- The canonical pitch representation is frequency in Hertz (Hz). For conversion, see+-- 'HasFrequency'. -- ------------------------------------------------------------------------------------- -module Music.Pitch.Absolute -- (--- )-where+module Music.Pitch.Absolute (+        Hertz(..),+        -- Octaves,+        Cents,+        Fifths,+        HasFrequency(..),+        -- octaves,+        fifths,+        cents,+  ) where  import Data.Maybe import Data.Either@@ -26,73 +36,72 @@ import Control.Monad import Control.Applicative --- | Frequency in Hertz    -newtype Frequency = Frequency { getFrequency :: Double }-    deriving ( Show, Eq, Enum, Num, Ord, Fractional, Floating )-+-- | +-- Absolute frequency in Hertz.    +newtype Hertz = Hertz { getHertz :: Double }+    deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac) --- | Logarithmic pitch reprentation.+-- | +-- Number of pure octaves. ----- > convert (f * 2) = convert f + Octaves 1    -newtype Octaves = Octaves { getOctaves :: Frequency }-    deriving ( Show, Eq, Enum, Num, Ord, Fractional, Floating )+-- Octaves are a logarithmic representation of frequency such that+--+-- > f * (2/1) = frequency (octaves f + 1)    +newtype Octaves = Octaves { getOctaves :: Hertz }+    deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac) --- | Logarithmic pitch reprentation.+-- | +-- Number of pure octaves. ----- > convert (f * 2) = convert f + Octave 1    -newtype Fifths = Fifths { getFifths :: Frequency }-    deriving ( Show, Eq, Enum, Num, Ord, Fractional, Floating )+-- Cents are a logarithmic representation of frequency such that+--+-- > f * (2/1) = frequency (cents f + 1200)    +newtype Cents = Cents { getCents :: Hertz }+    deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac) --- | Logarithmic pitch reprentation.    +-- | +-- Number of pure fifths. ----- > convert (f * 2) = convert f + Cent 1200    -newtype Cents = Cents { getCents :: Frequency }-    deriving ( Show, Eq, Enum, Num, Ord, Fractional, Floating )+-- Fifths are a logarithmic representation of frequency.+--+-- > f * (3/2) = frequency (fifths f + 1)    +newtype Fifths = Fifths { getFifths :: Hertz }+    deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac) -class HasFrequence a where-    frequency :: a -> Frequency --- instance Convert Frequency Octave where---     convert f             =  Octave (logBase 2 f)---     reconvert (Octave f)  =  2 ** f--- --- instance Convert Cent Octave where---     convert (Cent f)      =  Octave (f / 1200)---     reconvert (Octave f)  =  Cent   (f * 1200)--- --- instance Convert Frequency Cent where---     convert f             =  Cent   (logBase 2 f * 1200)---     reconvert (Cent f)    =  2 ** (f / 1200)--- --- instance Convert Octave Frequency where---     convert = reconvert---     reconvert = convert--- --- instance Convert Octave Cent where---     convert = reconvert---     reconvert = convert--- --- instance Convert Cent Frequency where---     convert = reconvert---     reconvert = convert-    +instance Semigroup Hertz    where (<>) = (*)+instance Semigroup Octaves  where (<>) = (+)+instance Semigroup Fifths   where (<>) = (+)+instance Semigroup Cents    where (<>) = (+) -cents :: HasFrequence a => a -> Cents-cents = undefined +instance Monoid Hertz       where { mempty  = 1 ; mappend = (*) }+instance Monoid Octaves     where { mempty  = 0 ; mappend = (+) }+instance Monoid Fifths      where { mempty  = 0 ; mappend = (+) }+instance Monoid Cents       where { mempty  = 0 ; mappend = (+) } -fifths :: HasFrequence a => a -> Fifths-fifths = undefined +class HasFrequency a where+    frequency :: a -> Hertz -octaves :: HasFrequence a => a -> Octaves-octaves = undefined +instance HasFrequency Hertz where+    frequency = id --- unitFrequency :: Frequency--- unitFrequency = 1+instance HasFrequency Octaves where+    frequency (Octaves f)  = (2/1) ** f --- unitOctave :: Octave--- unitOctave = Octave 0+instance HasFrequency Fifths where+    frequency (Fifths f)   =  (3/2) ** f --- unitCent :: Cent--- unitCent = Cent 0+instance HasFrequency Cents where+    frequency (Cents f)    =  (2/1) ** (f / 1200)++octaves :: HasFrequency a => a -> Octaves+octaves a = Octaves $ logBase (2/1) (frequency a)++fifths :: HasFrequency a => a -> Fifths+fifths a = Fifths $ logBase (3/2) (frequency a)++cents :: HasFrequency a => a -> Cents+cents a = Cents $ logBase (2/1) (frequency a) * 1200+                               
src/Music/Pitch/Intonation.hs view
@@ -22,4 +22,15 @@ import Data.Semigroup import Control.Monad import Control.Applicative+import Music.Pitch.Absolute +type Intonation a = a -> Hertz++pure :: Integral a => Intonation a+pure = undefined++pythagorean :: Integral a => Intonation a+pythagorean = undefined++twelveToneEqual :: Integral a => Intonation a+twelveToneEqual = undefined
src/Music/Pitch/Relative.hs view
@@ -1,4 +1,13 @@ +{-# LANGUAGE+    GeneralizedNewtypeDeriving,+    FlexibleInstances,+    DeriveFunctor,+    TypeFamilies,+    StandaloneDeriving,+    OverloadedStrings,+    DeriveFoldable #-}+ ------------------------------------------------------------------------------------- -- | -- Copyright   : (c) Hans Hoglund 2012@@ -13,13 +22,161 @@ -- ------------------------------------------------------------------------------------- -module Music.Pitch.Relative -- (--- )+module Music.Pitch.Relative (+    module Music.Pitch.Relative.Accidental,+    module Music.Pitch.Relative.Interval,+    module Music.Pitch.Relative.Name,+    module Music.Pitch.Relative.Number,+    module Music.Pitch.Relative.Pitch,+    module Music.Pitch.Relative.Quality,+    module Music.Pitch.Relative.Semitones,+) where  import Data.Maybe import Data.Either import Data.Semigroup+import Data.VectorSpace+import Data.AffineSpace import Control.Monad import Control.Applicative+import Music.Pitch.Absolute hiding (Octaves(..), octaves)+import Music.Pitch.Literal+import qualified Data.List as List +import Music.Pitch.Relative.Semitones+import Music.Pitch.Relative.Accidental+import Music.Pitch.Relative.Quality+import Music.Pitch.Relative.Name+import Music.Pitch.Relative.Number+import Music.Pitch.Relative.Pitch+import Music.Pitch.Relative.Interval+++{-  +    Some terminology:                                           +        +        newtype Pitch = (PitchClass, Semitones)+            For example (E, Natural)+            We write [c,cs,db..] for [(C, Natural), (C, Sharp), (D, Flat)..]+        +        newtype Interval = (Number, Semitones)+            For example (Augmented, IV)+        +        Interval is the relative representation of pitch +        +        Pitch is an affine space with Interval as the difference type+            c           .+^ major third = e+            major third ^+^ major third = augmentedFifth+        ++        Pitch addition and enhamonic equivalence:++++        +        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 `intervals`+            intervals :: Semitones -> [Interval]+            intervals 4 = [majorThird, diminishedFourth]+        Law+            map semitones (intervals a) = replicate n a    for all n > 0+        Lemma+            map semitones (intervals 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)++    Tonal+        isConsonance :: Interval -> Bool+        isPerfectConsonance :: Interval -> Bool+        isImperfectConsonance :: Interval -> Bool+        isDissonance :: Interval -> Bool+        isDissonance :: Interval -> Bool+        isHemitonic :: Interval -> Bool+        isTritonic :: Interval -> Bool++        isSemitone :: Interval -> Bool+        isSemitone :: Interval -> Bool+        isLeap :: Interval -> Bool+        isSimple :: Interval -> Bool+        isCompound :: Interval -> Bool+        +        -- 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)
+ src/Music/Pitch/Relative/Accidental.hs view
@@ -0,0 +1,72 @@++{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving, FlexibleInstances #-}++module Music.Pitch.Relative.Accidental (+        -- * Alterable class+        Alterable(..),++        -- * Accidentals+        Accidental,+        doubleFlat, +        flat, +        natural, +        sharp, +        doubleSharp,+  ) where++import Music.Pitch.Literal++-- |+-- Class of things that can be altered.+--+class Alterable a where+    -- | +    -- Increase the given pitch by one.+    -- +    sharpen :: a -> a++    -- | +    -- Decrease the given pitch by one.+    -- +    flatten :: a -> a++newtype Accidental = Accidental { getAccidental :: Integer }+    deriving (Eq, Ord, Num, Enum, Real, Integral)+    +instance Show Accidental where+    show n | n == 0 = "natural"+           | n > 0  = replicate' n 's'+           | n < 0  = replicate' (negate n) 'b'++instance Alterable Accidental where+    sharpen = succ+    flatten = pred++instance Alterable Double where+    sharpen = (+ 1)+    flatten = (subtract 1)++instance Alterable Integer where+    sharpen = (+ 1)+    flatten = (subtract 1)++instance (IsPitch a, Alterable a) => IsPitch (Accidental -> a) where+    fromPitch l acc+        | acc == sharp  = sharpen (fromPitch l)+        | acc == flat   = flatten (fromPitch l)++sharp, flat, natural, doubleFlat, doubleSharp :: Accidental+-- | The double sharp accidental.+doubleSharp = 2+-- | The sharp accidental.+sharp       = 1+-- | The natural accidental.+natural     = 0+-- | The flat accidental.+flat        = -1+-- | The double flat accidental.+doubleFlat  = -2+++replicate' n = replicate (fromIntegral n)+
+ src/Music/Pitch/Relative/Interval.hs view
@@ -0,0 +1,380 @@++{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving, TypeFamilies #-}++module Music.Pitch.Relative.Interval (+        -- ** Intervals+        Interval,++        -- *** Creating intervals+        interval,+        perfect,+        major,+        minor,+        augmented,+        diminished,+        doublyAugmented,+        doublyDiminished,++        -- *** Inspecting intervals+        number,+        -- isPerfectUnison,+        isPositive,+        isNegative,++        -- *** Simple and compound intervals+        isSimple,+        isCompound,+        separate,+        simple,++        -- *** Inversion+        invert,+++        -- * Utility+        -- ** Spelling+        Spelling,+        spell,+        sharps,+        flats,++        -- * Literals (TODO move)+        d1, _P1, _A1,+        d2, m2, _M2, _A2,+        d3, m3, _M3, _A3,+        d4, _P4, _A4,+        d5, _P5, _A5,+        d6, m6, _M6, _A6,+        d7, m7, _M7, _A7,+        d8, _P8, _A8,++        -- TODO+        intervalDiff,+        interval',+        octave,+  ) where++import Data.Maybe+import Data.Either+import Data.Semigroup+import Data.VectorSpace+import Data.AffineSpace+import Control.Monad+import Control.Applicative+import Music.Pitch.Absolute hiding (Octaves(..), octaves)+import Music.Pitch.Literal+import qualified Data.List as List++import Music.Pitch.Relative.Quality+import Music.Pitch.Relative.Semitones+import Music.Pitch.Relative.Number++-- |+-- An interval is the difference between two pitches, incuding negative+-- intervals.+--+-- Intervals and pitches can be added using '.+^'. To get the interval between+-- two pitches, use '.-.'.+--+-- > c .+^ minor third == eb+-- > f .-. c           == perfect fourth+--+-- Adding intervals preserves spelling. For example:+--+-- > m3 ^+^ _M3 = _P5+-- > d5 ^+^ _M6 = m10+--+-- The scalar type of intervals are 'Integer', using '^*' to stack intervals+-- of a certain type on top of each other. For example @_P5 ^* 2@ is a stack+-- of 2 perfect fifths. The 'Num' instance works as expected for '+', 'negate'+-- and 'abs', and arbitrarily uses octaves for multiplication. If you find+-- yourself '*', or 'signum' on intervals, consider switching to '^*' or+-- 'normalized'.+--+-- Intervals are generally described in terms of 'Quality' and 'Number'. To+-- construct an interval, use the 'interval' constructor, the utility+-- constructors 'major', 'minor', 'augmented' and 'diminished', or the+-- interval literals:+--+-- > m5  == minor   fifth    == interval Minor   5+-- > _P4 == perfect fourth   == interval Perfect 5+-- > d5  == diminished fifth == diminish (perfect fifth)+--+newtype Interval = Interval { getInterval :: (+            Int,        -- octaves, may be negative+            Int,        -- diatonic semitone [0..6]+            Int         -- chromatic semitone [0..11]+    ) }+    deriving (Eq, Ord)++instance Num Interval where+    (+)           = addInterval+    negate        = negateInterval+    abs a         = if isNegative a then negate a else a+    a * b         = fromIntegral (semitones a `div` 12) `stackInterval` b+    signum a      = if isNegative a then (-_P8) else _P8+    fromInteger 0 = _P1+    fromInteger _ = undefined++instance Show Interval where+    show a | isNegative a = "-" ++ show (quality a) ++ show (abs $ number a)+           | otherwise    =        show (quality a) ++ show (abs $ number a)++instance Semigroup Interval where+    (<>)    = addInterval++instance Monoid Interval where+    mempty  = perfect unison+    mappend = addInterval++instance AdditiveGroup Interval where+    zeroV   = perfect unison+    (^+^)   = addInterval+    negateV = negateInterval++instance VectorSpace Interval where+    type Scalar Interval = Integer+    (*^) = stackInterval++instance HasQuality Interval where+    quality (Interval (o, d, c))+        | o >= 0    =                 diffToQuality (isPerfectNumber d) (c - diatonicToChromatic d)+        | otherwise = invertQuality $ diffToQuality (isPerfectNumber d) (c - diatonicToChromatic d)++instance Augmentable Interval where+    augment  (Interval (o, d, c)) = Interval (o, d, c + 1)+    diminish (Interval (o, d, c)) = Interval (o, d, c - 1)++instance HasOctaves Interval where+    octaves = fst . separate++instance HasSemitones Interval where+    semitones (Interval (o, d, c)) = fromIntegral $ o * 12 + c++instance HasSteps Interval where+    steps a = fromIntegral $ semitones a `mod` 12++intervalDiff :: Interval -> Int+intervalDiff (Interval (o, d, c)) = c - diatonicToChromatic d++-- |+-- Creates an interval from a quality and number.+--+-- If given 'Perfect' with an imperfect number (such as 3 or 7) a major interval is+-- returned. If given 'Major' or 'Minor' with a perfect number (such as 5), constructs+-- a perfect or diminished interval respectively.+--+interval :: Quality -> Number -> Interval+interval quality number = interval' (qualityToDiff (isPerfectNumber diatonic) quality) (fromIntegral number)+    where+        (_, diatonic) = (fromIntegral $ number - 1) `divMod` 7++interval' :: Int -> Int -> Interval+interval' diff number = Interval (octave, diatonic, diatonicToChromatic diatonic + diff)+    where+        (octave, diatonic) = (number - 1) `divMod` 7+++-- | Creates a perfect interval.+--   If given an inperfect number, constructs a major interval.+perfect    = interval Perfect+-- | Creates a major interval.+--   If given a perfect number, constructs a perfect interval.+major      = interval Major+-- | Creates a minor interval.+--   If given a perfect number, constructs a diminished interval.+minor      = interval Minor+-- | Creates an augmented interval.+augmented  = interval (Augmented 1)+-- | Creates a diminished interval.+diminished = interval (Diminished 1)+-- | Creates a doubly augmented interval.+doublyAugmented  = interval (Augmented 2)+-- | Creates a doubly diminished interval.+doublyDiminished = interval (Diminished 2)+++invertDiatonic :: Num a => a -> a+invertDiatonic d  = 7  - d++invertChromatic :: Num a => a -> a+invertChromatic c = 12 - c++negateInterval :: Interval -> Interval+negateInterval (Interval (o, 0, 0))   = Interval (negate o, 0, 0)+negateInterval (Interval (oa, da,ca)) = Interval (negate (oa + 1), invertDiatonic da, invertChromatic ca)++addInterval :: Interval -> Interval -> Interval+addInterval (Interval (oa, da,ca)) (Interval (ob, db,cb))+    = Interval (oa + ob + carry, steps, chroma)+    where+        (carry, steps) = (da + db) `divMod` 7+        chroma         = trunc (ca + cb)+        trunc          = if carry > 0 then (`mod` 12) else id++stackInterval :: Integer -> Interval -> Interval+stackInterval n a | n >= 0    = mconcat $ replicate (fromIntegral n) a+                  | otherwise = negate $ stackInterval (negate n) a++-- |+-- Separate a compound interval into octaves and a simple interval.+--+-- > (perfect octave)^*x + y = z  iff  (x, y) = separate z+--+separate :: Interval -> (Octaves, Interval)+separate (Interval (o, d, c)) = (fromIntegral o, Interval (0, d, c))++-- |+-- Returns the simple part of an interval.+--+-- > (perfect octave)^*x + y = z  iff  y = simple z+--+simple :: Interval -> Interval+simple = snd . separate+++-- |+-- Returns the number portion of an interval.+--+-- The interval number is negative if and only if the interval is negative.+--+-- See also 'quality', 'octaves' and 'semitones'.+--+number :: Interval -> Number+number (Interval (o, d, c)) = fromIntegral $ inc $ o * 7 + d+    where+        inc a = if a >= 0 then succ a else pred a++++-- |+-- Returns whether the given interval is simple.+--+-- A simple interval is an positive interval spanning less than one octave.+--+isSimple :: Interval -> Bool+isSimple = (== 0) . octaves++-- |+-- Returns whether the given interval is compound.+--+-- A compound interval is either a negative interval, or a positive interval spanning+-- more than octave.+--+isCompound :: Interval -> Bool+isCompound = (/= 0) . octaves++isPerfectUnison :: Interval -> Bool+isPerfectUnison a = a == perfect unison++-- |+-- Returns whether the given interval is positive.+--+isPositive :: Interval -> Bool+isPositive (Interval (oa, _, _)) = oa > 0++-- |+-- Returns whether the given interval is negative.+--+isNegative :: Interval -> Bool+isNegative (Interval (oa, _, _)) = oa < 0+++-- |+-- Intervallic inversion.+--+-- The inversion of a simple interval is determined by the following rules:+--+-- * The interval number and the number of its inversion always add up to nine+--   (i.e. 4 + 5 = 9).+--+-- * The inversion of a major interval is a minor interval, and vice versa;+--   the inversion of a perfect interval is also perfect; the inversion of an+--   augmented interval is a diminished interval, and vice versa; the+--   inversion of a doubly augmented interval is a doubly diminished interval,+--   and vice versa.+--+-- The inversion of any compound interval is always the same as the inversion+-- of the simple interval from which it is compounded, i.e.:+--+-- > invert = simple . negate+--+invert :: Interval -> Interval+invert = simple . negate++++type Spelling = Semitones -> Number++spell :: HasSemitones a => Spelling -> a -> Interval+spell z = (\s -> Interval (fromIntegral $ s `div` 12, fromIntegral $ z s, fromIntegral s)) .  semitones++isPerfectNumber :: Int -> Bool+isPerfectNumber 0 = True+isPerfectNumber 1 = False+isPerfectNumber 2 = False+isPerfectNumber 3 = True+isPerfectNumber 4 = True+isPerfectNumber 5 = False+isPerfectNumber 6 = False++diatonicToChromatic :: Int -> Int+diatonicToChromatic = go+    where+        go 0 = 0+        go 1 = 2+        go 2 = 4+        go 3 = 5+        go 4 = 7+        go 5 = 9+        go 6 = 11++sharps :: Semitones -> Number+sharps = go+    where+        go 0  = 0+        go 1  = 0+        go 2  = 1+        go 3  = 1+        go 4  = 2+        go 5  = 3+        go 6  = 3+        go 7  = 4+        go 8  = 4+        go 9  = 5+        go 10 = 5+        go 11 = 6++flats :: Semitones -> Number+flats = go+    where+        go 0  = 0+        go 1  = 1+        go 2  = 1+        go 3  = 2+        go 4  = 2+        go 5  = 3+        go 6  = 4+        go 7  = 4+        go 8  = 5+        go 9  = 5+        go 10 = 6+        go 11 = 6+++++_ = 1 ;                  d1 = Interval (0,0,-1) ; _P1 = Interval (0,0,0)  ; _A1 = Interval (0,0,1)+d2 = Interval (0,1,0)  ; m2 = Interval (0,1,1)  ; _M2 = Interval (0,1,2)  ; _A2 = Interval (0,1,3)+d3 = Interval (0,2,2)  ; m3 = Interval (0,2,3)  ; _M3 = Interval (0,2,4)  ; _A3 = Interval (0,2,5)+_ = 1 ;                  d4 = Interval (0,3,4)  ; _P4 = Interval (0,3,5)  ; _A4 = Interval (0,3,6)+_ = 1 ;                  d5 = Interval (0,4,6)  ; _P5 = Interval (0,4,7)  ; _A5 = Interval (0,4,8)+d6 = Interval (0,5,7)  ; m6 = Interval (0,5,8)  ; _M6 = Interval (0,5,9)  ; _A6 = Interval (0,5,10)+d7 = Interval (0,6,9)  ; m7 = Interval (0,6,10) ; _M7 = Interval (0,6,11) ; _A7 = Interval (0,6,12)+_ = 1 ;                  d8 = Interval (1,0,-1) ; _P8 = Interval (1,0,0)  ; _A8 = Interval (1,0,1)++d9  = d2  + _P8 ; m9  = m2  + _P8 ; _M9  = _M2 + _P8 ; _A9  = _A2 + _P8+d10 = d3  + _P8 ; m10 = m3  + _P8 ; _M10 = _M3 + _P8 ; _A10 = _A3 + _P8+++
+ src/Music/Pitch/Relative/Name.hs view
@@ -0,0 +1,20 @@+ +{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving #-}++module Music.Pitch.Relative.Name (+        -- ** Name+        Name(..),+  ) where++instance Show Name where+    show C = "c"+    show D = "d"+    show E = "e"+    show F = "f"+    show G = "g"+    show A = "a"+    show B = "b"++data Name = C | D | E | F | G | A | B+    deriving (Eq, Ord, Enum)+
+ src/Music/Pitch/Relative/Number.hs view
@@ -0,0 +1,56 @@++{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving #-}++module Music.Pitch.Relative.Number (+        -- ** Number+        Number,   +        unison,+        prime,+        second,+        third,+        fourth,+        fifth,+        sixth,+        seventh,+        octave,+        -- ninth,+        -- tenth,+        -- twelfth,+        -- thirteenth,+        -- fourteenth,+        -- duodecim,+  ) where++-- |+-- The number portion of an interval (i.e. second, third, etc).+--+-- Note that the interval number is always one step larger than number of steps spanned by+-- the interval (i.e. a third spans two diatonic steps). Thus 'number' does not distribute+-- over addition:+--+-- > number (a + b) = number a + number b - 1+--+newtype Number = Number { getNumber :: Integer }+    deriving (Eq, Ord, Num, Enum, Real, Integral)+    +instance Show Number where { show = show . getNumber }++unison  :: Number+prime   :: Number+second  :: Number+third   :: Number+fourth  :: Number+fifth   :: Number+sixth   :: Number+seventh :: Number+octave  :: Number+unison  = 1+prime   = 1+second  = 2+third   = 3+fourth  = 4+fifth   = 5+sixth   = 6+seventh = 7+octave  = 8+
+ src/Music/Pitch/Relative/Pitch.hs view
@@ -0,0 +1,148 @@++{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving, TypeFamilies #-}++module Music.Pitch.Relative.Pitch (+        -- * Pitch+        Pitch,    +        pitch,+        name,+        accidental,+        asPitch,+  ) where++import Data.Maybe+import Data.Either+import Data.Semigroup+import Data.VectorSpace+import Data.AffineSpace+import Control.Monad+import Control.Applicative+import Music.Pitch.Absolute hiding (Octaves(..), octaves)+import Music.Pitch.Literal+import qualified Data.List as List++import Music.Pitch.Relative.Interval+import Music.Pitch.Relative.Quality+import Music.Pitch.Relative.Accidental+import Music.Pitch.Relative.Semitones+import Music.Pitch.Relative.Name++-- |+-- Standard pitch representation.+--+-- Intervals and pitches can be added using '.+^'. To get the interval between+-- two pitches, use '.-.'.+--+-- Notes with accidentals can be written by adding the @s@ or @b@ suffices+-- (or two for double sharps and flats).+--+-- > cs, ds, es ...    -- sharp+-- > cb, db, eb ...    -- flat+-- > css, dss, ess ... -- double sharp+-- > cbb, dbb, ebb ... -- double flat+--+-- There is also a convenience syntax for entering pitches one octave up or+-- down, using @'@ and @_@ respectively.+--+-- > g a b c'+-- > d c b_ c+--+-- Because of some overloading magic, we can actually write @sharp@ and+-- @flat@ as /postfix/ functions. This gives a better read:+--+-- > cs == c sharp+-- > db == c flat+--+-- You can of course use typical functional transformation of pitch as well.+-- For example 'sharpen' and 'flatten' are the ordinary (prefix) versions of+-- 'sharp' and 'flat'+--+-- > sharpen c             == c sharp       == cs+-- > flatten d             == d flat        == ds+-- > (sharpen . sharpen) c == c doubleSharp == css+-- > (flatten . flatten) d == d doubleFlat  == dss+--+-- Note that there is no guarantee that your pitch representation use+-- enharmonic equivalence, so @cs == db@ may or may not hold.+--+-- > c .+^ minor third == eb+-- > f .-. c           == perfect fourth+--+-- Pitches are described by name, accidental and octave number.+--+-- > c   == fromIntegral 0+-- > _P4 == perfect fourth   == interval Perfect 5+-- > d5  == diminished fifth == diminish (perfect fifth)+--+newtype Pitch = Pitch { getPitch :: Interval }+    deriving (Eq, Num, Ord)+    +instance AffineSpace Pitch where+    type Diff Pitch     = Interval+    Pitch a .-. Pitch b = a ^-^ b+    Pitch a .+^ b       = Pitch (a ^+^ b)++instance Show Pitch where+    show p = show (name p) ++ showAccidental (accidental p) ++ showOctave (octaves p)+        where+            showOctave n+                | n > 0     = replicate' n '\''+                | otherwise = replicate' (negate n) '_'+            showAccidental n+                | n > 0     = replicate' n 's'+                | otherwise = replicate' (negate n) 'b'++instance Alterable Pitch where+    sharpen (Pitch a) = Pitch (augment a)+    flatten (Pitch a) = Pitch (diminish a)++-- |+-- This is just the identity function, but is useful to fix the type of 'Pitch'.+--+asPitch :: Pitch -> Pitch+asPitch = id++-- |+-- Creates a pitch from name accidental.+--+pitch :: Name -> Accidental -> Pitch+pitch = undefined++-- |+-- Returns the name of a pitch.+--+-- See also 'octaves', and 'steps' and 'semitones'.+--+name :: Pitch -> Name+name = toEnum . fromIntegral . pred . number . simple . getPitch++-- |+-- Returns the accidental of a pitch.+--+-- See also 'octaves', and 'steps' and 'semitones'.+--+accidental :: Pitch -> Accidental+accidental = fromIntegral . intervalDiff . simple . getPitch++instance HasOctaves Pitch where+    octaves = octaves . getPitch++instance HasSemitones Pitch where+    semitones = semitones . getPitch++instance HasSteps Pitch where+    steps = steps . getPitch+++instance IsPitch Pitch where+    fromPitch (PitchL (c, a, o)) =+        Pitch $ interval' (qual a) (c + 1)+            ^+^+            (perfect octave^* fromIntegral (o - 4))+        where+            qual Nothing  = 0+            qual (Just n) = round n++midiNumber :: Pitch -> Integer+midiNumber = fromIntegral . semitones . getPitch+
+ src/Music/Pitch/Relative/Quality.hs view
@@ -0,0 +1,156 @@++{-# 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)
+ src/Music/Pitch/Relative/Semitones.hs view
@@ -0,0 +1,163 @@++{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving #-}++module Music.Pitch.Relative.Semitones (+        -- * Octaves+        Octaves,+        HasOctaves(..),++        -- * Steps+        Steps,+        HasSteps(..),++        -- * Semitones+        Semitones,+        HasSemitones(..),+        semitone,+        tone,+        ditone,+        tritone,+        isSemitone,+        isTone,+        isTritone,+        +        -- ** Enharmonic equivalence+        (=:=),+        (/:=),+  ) where++-- |+-- An interval represented as a number of octaves, including negative+-- intervals.+--+-- > octaves a = semitones a `div` 12+-- > steps   a = semitones a `mod` 12+--+newtype Octaves = Octaves { getOctaves :: Integer }     +    deriving (Eq, Ord, Num, Enum, Real, Integral)++instance Show       Octaves where { show = show . getOctaves }+instance HasOctaves Octaves where { octaves = id }++-- |+-- Class of intervals that has a number of 'Octaves'.+--+class HasOctaves a where+    -- |+    -- Returns the number of octaves spanned by an interval.+    --+    -- The number of octaves is negative if and only if the interval is+    -- negative.+    --+    -- Examples:+    --+    -- > octaves (perfect unison)  =  0+    -- > octaves (d5 ^* 4)         =  2+    -- > octaves (-_P8)            =  -1+    --+    octaves :: a -> Octaves+++-- |+-- An interval represented as a number of steps in the range /0 ≤ x < 12/.+--+-- > octaves a = semitones a `div` 12+-- > steps   a = semitones a `mod` 12+--+newtype Steps = Steps { getSteps :: Integer }+    deriving (Eq, Ord, Num, Enum, Real, Integral)++instance Show     Steps where { show = show . getSteps }+instance HasSteps Steps where { steps = id }++-- |+-- Class of intervals that has a number of 'Steps'.+--+class HasSteps a where+    -- |+    -- The number of steps is always in the range /0 ≤ x < 12/.+    --+    -- Examples:+    --+    -- > octaves (perfect unison)  =  0+    -- > octaves (d5 ^* 4)         =  2+    -- > octaves (-m7)             =  -1+    --+    steps :: a -> Steps++-- |+-- An interval represented as a number of semitones, including negative+-- intervals, as well as intervals larger than one octave. This representation+-- does not take spelling into account, so for example a major third and a+-- diminished fourth can not be distinguished.+--+-- Intervals that name a number of semitones (i.e. 'semitone', 'tritone') does+-- not have an unequivocal spelling. To convert these to an interval, a+-- 'Spelling' must be provided as in:+--+-- > spell sharps tritone == augmented fourth+-- > spell flats  tritone == diminished fifth+--+newtype Semitones = Semitones { getSemitones :: Integer }+    deriving (Eq, Ord, Num, Enum, Real, Integral)++instance Show         Semitones where { show = show . getSemitones }+instance HasSemitones Semitones where { semitones = id }++-- |+-- Class of intervals that can be converted to a number of 'Semitones'.+--+class HasSemitones a where++    -- |+    -- Returns the number of semitones spanned by an interval.+    --+    -- The number of semitones is negative if and only if the interval is+    -- negative.+    --+    -- Examples:+    --+    -- > semitones (perfect unison)  =  0+    -- > semitones tritone           =  6+    -- > semitones d5                =  6+    -- > semitones (-_P8)            =  -12+    --+    semitones :: a -> Semitones+++semitone, tone, ditone, tritone :: Semitones++-- | Precisely one semitone.+semitone = 1+-- | Precisely one whole tone, or two semitones.+tone     = 2+-- | Precisely two whole tones, or four semitones.+ditone   = 4+-- | Precisely three whole tones, or six semitones.+tritone  = 6++isTone, isSemitone, isTritone :: HasSemitones a => a -> Bool+-- | Returns true iff the given interval spans one semitone.+isSemitone  = (== semitone) . abs . semitones+-- | Returns true iff the given interval spans one whole tone (two semitones).+isTone      = (== tone)     . abs . semitones+-- | Returns true iff the given interval spans three whole tones (six semitones).+isTritone   = (== tritone)  . abs . semitones+++infix 4 =:=+infix 4 /:=++-- |+-- Enharmonic equivalence.+--+(=:=) :: HasSemitones a => a -> a -> Bool+a =:= b = semitones a == semitones b++-- |+-- Enharmonic non-equivalence.+--+(/:=) :: HasSemitones a => a -> a -> Bool+a /:= b = semitones a /= semitones b++